10Sstevel@tonic-gate/* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1614Sjb145095 * Common Development and Distribution License (the "License"). 6*1614Sjb145095 * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate/* 22*1614Sjb145095 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate#ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate#include <sys/asm_linkage.h> 290Sstevel@tonic-gate#include <sys/trap.h> 300Sstevel@tonic-gate#include <sys/machpcb.h> 31*1614Sjb145095#include <sys/machtrap.h> 32*1614Sjb145095#include <sys/machsig.h> 33*1614Sjb145095#include <sys/machthread.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate#if !defined(lint) && !defined(__lint) 360Sstevel@tonic-gate#include "assym.h" 370Sstevel@tonic-gate#endif /* lint */ 380Sstevel@tonic-gate 390Sstevel@tonic-gate/* 400Sstevel@tonic-gate * Floating point trap handling. 410Sstevel@tonic-gate * 420Sstevel@tonic-gate * The FPU is always in a V9 current configuration. 430Sstevel@tonic-gate * 440Sstevel@tonic-gate * When a user process is first started via exec, 450Sstevel@tonic-gate * floating point operations will be disabled by default. 460Sstevel@tonic-gate * Upon execution of the first floating point instruction, 470Sstevel@tonic-gate * a fp_disabled trap will be generated; then a word in 480Sstevel@tonic-gate * the uarea is written signifying use of the floating point 490Sstevel@tonic-gate * registers so that subsequent context switches will save 500Sstevel@tonic-gate * and restore the floating point them. The trapped instruction 510Sstevel@tonic-gate * will be restarted and processing will continue as normal. 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * When a operation occurs that the hardware cannot properly 540Sstevel@tonic-gate * handle, an unfinshed fp_op exception will be generated. 550Sstevel@tonic-gate * Software routines in the kernel will be executed to 560Sstevel@tonic-gate * simulate proper handling of such conditions. 570Sstevel@tonic-gate * 580Sstevel@tonic-gate * Exception handling will emulate all instructions 590Sstevel@tonic-gate * in the floating point address queue. Note that there 600Sstevel@tonic-gate * is no %fq in sun4u, because it has precise FP traps. 610Sstevel@tonic-gate * 620Sstevel@tonic-gate * Floating point queues are now machine dependent, and std %fq 630Sstevel@tonic-gate * is an illegal V9 instruction. The fp_exception code has been 640Sstevel@tonic-gate * moved to sun4u/ml/machfloat.s. 650Sstevel@tonic-gate * 660Sstevel@tonic-gate * NOTE: This code DOES NOT SUPPORT KERNEL (DEVICE DRIVER) 670Sstevel@tonic-gate * USE OF THE FPU 680Sstevel@tonic-gate * 690Sstevel@tonic-gate * Instructions for running without the hardware fpu: 700Sstevel@tonic-gate * 1. Setting fpu_exists to 0 now only works on a DEBUG kernel. 710Sstevel@tonic-gate * 2. adb -w unix and set fpu_exists, use_hw_bcopy, use_hw_copyio, and 720Sstevel@tonic-gate * use_hw_bzero to 0 and rename libc_psr.so.1 in 730Sstevel@tonic-gate * /usr/platform/sun4u/lib so that it will not get used by 740Sstevel@tonic-gate * the libc bcopy routines. Then reboot the system and you 750Sstevel@tonic-gate * should see the bootup message "FPU not in use". 760Sstevel@tonic-gate * 3. To run kaos, you must comment out the code which sets the 770Sstevel@tonic-gate * version number of the fsr to 7, in fldst: stfsr/stxfsr 780Sstevel@tonic-gate * (unless you are running against a comparison system that 790Sstevel@tonic-gate * has the same fsr version number). 800Sstevel@tonic-gate * 4. The stqf{a}/ldqf{a} instructions cause kaos errors, for reasons 810Sstevel@tonic-gate * that appear to be a kaos bug, so don't use them! 820Sstevel@tonic-gate */ 830Sstevel@tonic-gate 840Sstevel@tonic-gate#if defined(lint) || defined(__lint) 850Sstevel@tonic-gate 860Sstevel@tonic-gate#ifdef FP_DISABLED 870Sstevel@tonic-gateint fpu_exists = 0; 880Sstevel@tonic-gate#else 890Sstevel@tonic-gateint fpu_exists = 1; 900Sstevel@tonic-gate#endif 910Sstevel@tonic-gate 920Sstevel@tonic-gate#else /* lint */ 930Sstevel@tonic-gate 940Sstevel@tonic-gate .section ".data" 950Sstevel@tonic-gate .align 8 960Sstevel@tonic-gatefsrholder: 970Sstevel@tonic-gate .word 0 ! dummy place to write fsr 980Sstevel@tonic-gate .word 0 990Sstevel@tonic-gate 1000Sstevel@tonic-gate DGDEF(fpu_exists) ! always exists for V9 1010Sstevel@tonic-gate#ifdef FP_DISABLED 1020Sstevel@tonic-gate .word 0 1030Sstevel@tonic-gate#else 1040Sstevel@tonic-gate .word 1 ! sundiag (gack) uses this variable 1050Sstevel@tonic-gate#endif 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate DGDEF(fpu_version) 1080Sstevel@tonic-gate .word -1 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate#endif /* lint */ 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate/* 1130Sstevel@tonic-gate * FPU probe - read the %fsr and get fpu_version. 1140Sstevel@tonic-gate * Called from autoconf. If a %fq is created for 1150Sstevel@tonic-gate * future cpu versions, a fq_exists variable 1160Sstevel@tonic-gate * could be created by this function. 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate#if defined(lint) || defined(__lint) 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate/*ARGSUSED*/ 1220Sstevel@tonic-gatevoid 1230Sstevel@tonic-gatefpu_probe(void) 1240Sstevel@tonic-gate{} 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate#else /* lint */ 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate ENTRY_NP(fpu_probe) 1290Sstevel@tonic-gate wr %g0, FPRS_FEF, %fprs ! enable fpu in fprs 1300Sstevel@tonic-gate rdpr %pstate, %g2 ! read pstate, save value in %g2 1310Sstevel@tonic-gate or %g2, PSTATE_PEF, %g1 ! new pstate with fpu enabled 1320Sstevel@tonic-gate wrpr %g1, %g0, %pstate ! write pstate 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate sethi %hi(fsrholder), %g2 1350Sstevel@tonic-gate stx %fsr, [%g2 + %lo(fsrholder)] 1360Sstevel@tonic-gate ldx [%g2 + %lo(fsrholder)], %g2 ! snarf the FSR 1370Sstevel@tonic-gate set FSR_VER, %g1 1380Sstevel@tonic-gate and %g2, %g1, %g2 ! get version 1390Sstevel@tonic-gate srl %g2, FSR_VER_SHIFT, %g2 ! and shift it down 1400Sstevel@tonic-gate sethi %hi(fpu_version), %g3 ! save the FPU version 1410Sstevel@tonic-gate st %g2, [%g3 + %lo(fpu_version)] 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate ba fp_kstat_init ! initialize the fpu_kstat 1440Sstevel@tonic-gate wr %g0, %g0, %fprs ! disable fpu and clear fprs 1450Sstevel@tonic-gate SET_SIZE(fpu_probe) 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate#endif /* lint */ 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate/* 1500Sstevel@tonic-gate * fp_clearregs(fp) 1510Sstevel@tonic-gate * struct v9_fpu *fp; 1520Sstevel@tonic-gate * 1530Sstevel@tonic-gate * Initialization for the hardware fpu. 1540Sstevel@tonic-gate * Clear the fsr and initialize registers to NaN (-1) 1550Sstevel@tonic-gate * The caller (fp_disabled) is supposed to update the fprs 1560Sstevel@tonic-gate * so when the return to userland is made, the fpu is enabled. 1570Sstevel@tonic-gate */ 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate#if defined(lint) || defined(__lint) 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate/*ARGSUSED*/ 1620Sstevel@tonic-gatevoid 1630Sstevel@tonic-gatefp_clearregs(kfpu_t *fp) 1640Sstevel@tonic-gate{} 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate#else /* lint */ 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate ENTRY_NP(fp_clearregs) 1690Sstevel@tonic-gate ldx [%o0 + FPU_FSR], %fsr ! load fsr 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate mov -1, %g2 ! -1 is NaN 1720Sstevel@tonic-gate stx %g2, [%o0] ! initialize %f0 1730Sstevel@tonic-gate ldd [%o0], %d0 1740Sstevel@tonic-gate ldd [%o0], %d2 1750Sstevel@tonic-gate ldd [%o0], %d4 1760Sstevel@tonic-gate ldd [%o0], %d6 1770Sstevel@tonic-gate ldd [%o0], %d8 1780Sstevel@tonic-gate ldd [%o0], %d10 1790Sstevel@tonic-gate ldd [%o0], %d12 1800Sstevel@tonic-gate ldd [%o0], %d14 1810Sstevel@tonic-gate ldd [%o0], %d16 1820Sstevel@tonic-gate ldd [%o0], %d18 1830Sstevel@tonic-gate ldd [%o0], %d20 1840Sstevel@tonic-gate ldd [%o0], %d22 1850Sstevel@tonic-gate ldd [%o0], %d24 1860Sstevel@tonic-gate ldd [%o0], %d26 1870Sstevel@tonic-gate ldd [%o0], %d28 1880Sstevel@tonic-gate ldd [%o0], %d30 1890Sstevel@tonic-gate ldd [%o0], %d32 1900Sstevel@tonic-gate ldd [%o0], %d34 1910Sstevel@tonic-gate ldd [%o0], %d36 1920Sstevel@tonic-gate ldd [%o0], %d38 1930Sstevel@tonic-gate ldd [%o0], %d40 1940Sstevel@tonic-gate ldd [%o0], %d42 1950Sstevel@tonic-gate ldd [%o0], %d44 1960Sstevel@tonic-gate ldd [%o0], %d46 1970Sstevel@tonic-gate ldd [%o0], %d48 1980Sstevel@tonic-gate ldd [%o0], %d50 1990Sstevel@tonic-gate ldd [%o0], %d52 2000Sstevel@tonic-gate ldd [%o0], %d54 2010Sstevel@tonic-gate ldd [%o0], %d56 2020Sstevel@tonic-gate ldd [%o0], %d58 2030Sstevel@tonic-gate ldd [%o0], %d60 2040Sstevel@tonic-gate retl 2050Sstevel@tonic-gate ldd [%o0], %d62 2060Sstevel@tonic-gate SET_SIZE(fp_clearregs) 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate#endif /* lint */ 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate/* 2110Sstevel@tonic-gate * void _fp_read_pfreg(pf, n) 2120Sstevel@tonic-gate * uint32_t *pf; Old freg value. 2130Sstevel@tonic-gate * unsigned n; Want to read register n 2140Sstevel@tonic-gate * 2150Sstevel@tonic-gate * { 2160Sstevel@tonic-gate * *pf = %f[n]; 2170Sstevel@tonic-gate * } 2180Sstevel@tonic-gate * 2190Sstevel@tonic-gate * void 2200Sstevel@tonic-gate * _fp_write_pfreg(pf, n) 2210Sstevel@tonic-gate * uint32_t *pf; New freg value. 2220Sstevel@tonic-gate * unsigned n; Want to write register n. 2230Sstevel@tonic-gate * 2240Sstevel@tonic-gate * { 2250Sstevel@tonic-gate * %f[n] = *pf; 2260Sstevel@tonic-gate * } 2270Sstevel@tonic-gate */ 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate#if defined(lint) || defined(__lint) 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate/*ARGSUSED*/ 2320Sstevel@tonic-gatevoid 2330Sstevel@tonic-gate_fp_read_pfreg(uint32_t *pf, u_int n) 2340Sstevel@tonic-gate{} 2350Sstevel@tonic-gate 2360Sstevel@tonic-gate/*ARGSUSED*/ 2370Sstevel@tonic-gatevoid 2380Sstevel@tonic-gate_fp_write_pfreg(uint32_t *pf, u_int n) 2390Sstevel@tonic-gate{} 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate#else /* lint */ 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate ENTRY_NP(_fp_read_pfreg) 2440Sstevel@tonic-gate sll %o1, 3, %o1 ! Table entries are 8 bytes each. 2450Sstevel@tonic-gate set .stable, %g1 ! g1 gets base of table. 2460Sstevel@tonic-gate jmp %g1 + %o1 ! Jump into table 2470Sstevel@tonic-gate nop ! Can't follow CTI by CTI. 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate ENTRY_NP(_fp_write_pfreg) 2500Sstevel@tonic-gate sll %o1, 3, %o1 ! Table entries are 8 bytes each. 2510Sstevel@tonic-gate set .ltable, %g1 ! g1 gets base of table. 2520Sstevel@tonic-gate jmp %g1 + %o1 ! Jump into table 2530Sstevel@tonic-gate nop ! Can't follow CTI by CTI. 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate#define STOREFP(n) jmp %o7+8 ; st %f/**/n, [%o0] 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate.stable: 2580Sstevel@tonic-gate STOREFP(0) 2590Sstevel@tonic-gate STOREFP(1) 2600Sstevel@tonic-gate STOREFP(2) 2610Sstevel@tonic-gate STOREFP(3) 2620Sstevel@tonic-gate STOREFP(4) 2630Sstevel@tonic-gate STOREFP(5) 2640Sstevel@tonic-gate STOREFP(6) 2650Sstevel@tonic-gate STOREFP(7) 2660Sstevel@tonic-gate STOREFP(8) 2670Sstevel@tonic-gate STOREFP(9) 2680Sstevel@tonic-gate STOREFP(10) 2690Sstevel@tonic-gate STOREFP(11) 2700Sstevel@tonic-gate STOREFP(12) 2710Sstevel@tonic-gate STOREFP(13) 2720Sstevel@tonic-gate STOREFP(14) 2730Sstevel@tonic-gate STOREFP(15) 2740Sstevel@tonic-gate STOREFP(16) 2750Sstevel@tonic-gate STOREFP(17) 2760Sstevel@tonic-gate STOREFP(18) 2770Sstevel@tonic-gate STOREFP(19) 2780Sstevel@tonic-gate STOREFP(20) 2790Sstevel@tonic-gate STOREFP(21) 2800Sstevel@tonic-gate STOREFP(22) 2810Sstevel@tonic-gate STOREFP(23) 2820Sstevel@tonic-gate STOREFP(24) 2830Sstevel@tonic-gate STOREFP(25) 2840Sstevel@tonic-gate STOREFP(26) 2850Sstevel@tonic-gate STOREFP(27) 2860Sstevel@tonic-gate STOREFP(28) 2870Sstevel@tonic-gate STOREFP(29) 2880Sstevel@tonic-gate STOREFP(30) 2890Sstevel@tonic-gate STOREFP(31) 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate#define LOADFP(n) jmp %o7+8 ; ld [%o0],%f/**/n 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate.ltable: 2940Sstevel@tonic-gate LOADFP(0) 2950Sstevel@tonic-gate LOADFP(1) 2960Sstevel@tonic-gate LOADFP(2) 2970Sstevel@tonic-gate LOADFP(3) 2980Sstevel@tonic-gate LOADFP(4) 2990Sstevel@tonic-gate LOADFP(5) 3000Sstevel@tonic-gate LOADFP(6) 3010Sstevel@tonic-gate LOADFP(7) 3020Sstevel@tonic-gate LOADFP(8) 3030Sstevel@tonic-gate LOADFP(9) 3040Sstevel@tonic-gate LOADFP(10) 3050Sstevel@tonic-gate LOADFP(11) 3060Sstevel@tonic-gate LOADFP(12) 3070Sstevel@tonic-gate LOADFP(13) 3080Sstevel@tonic-gate LOADFP(14) 3090Sstevel@tonic-gate LOADFP(15) 3100Sstevel@tonic-gate LOADFP(16) 3110Sstevel@tonic-gate LOADFP(17) 3120Sstevel@tonic-gate LOADFP(18) 3130Sstevel@tonic-gate LOADFP(19) 3140Sstevel@tonic-gate LOADFP(20) 3150Sstevel@tonic-gate LOADFP(21) 3160Sstevel@tonic-gate LOADFP(22) 3170Sstevel@tonic-gate LOADFP(23) 3180Sstevel@tonic-gate LOADFP(24) 3190Sstevel@tonic-gate LOADFP(25) 3200Sstevel@tonic-gate LOADFP(26) 3210Sstevel@tonic-gate LOADFP(27) 3220Sstevel@tonic-gate LOADFP(28) 3230Sstevel@tonic-gate LOADFP(29) 3240Sstevel@tonic-gate LOADFP(30) 3250Sstevel@tonic-gate LOADFP(31) 3260Sstevel@tonic-gate SET_SIZE(_fp_read_pfreg) 3270Sstevel@tonic-gate SET_SIZE(_fp_write_pfreg) 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate#endif /* lint */ 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate/* 3320Sstevel@tonic-gate * void _fp_read_pdreg( 3330Sstevel@tonic-gate * uint64_t *pd, Old dreg value. 3340Sstevel@tonic-gate * u_int n) Want to read register n 3350Sstevel@tonic-gate * 3360Sstevel@tonic-gate * { 3370Sstevel@tonic-gate * *pd = %d[n]; 3380Sstevel@tonic-gate * } 3390Sstevel@tonic-gate * 3400Sstevel@tonic-gate * void 3410Sstevel@tonic-gate * _fp_write_pdreg( 3420Sstevel@tonic-gate * uint64_t *pd, New dreg value. 3430Sstevel@tonic-gate * u_int n) Want to write register n. 3440Sstevel@tonic-gate * 3450Sstevel@tonic-gate * { 3460Sstevel@tonic-gate * %d[n] = *pd; 3470Sstevel@tonic-gate * } 3480Sstevel@tonic-gate */ 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate#if defined(lint) || defined(__lint) 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate/*ARGSUSED*/ 3530Sstevel@tonic-gatevoid 3540Sstevel@tonic-gate_fp_read_pdreg(uint64_t *pd, u_int n) 3550Sstevel@tonic-gate{} 3560Sstevel@tonic-gate 3570Sstevel@tonic-gate/*ARGSUSED*/ 3580Sstevel@tonic-gatevoid 3590Sstevel@tonic-gate_fp_write_pdreg(uint64_t *pd, u_int n) 3600Sstevel@tonic-gate{} 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate#else /* lint */ 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate ENTRY_NP(_fp_read_pdreg) 3650Sstevel@tonic-gate sll %o1, 3, %o1 ! Table entries are 8 bytes each. 3660Sstevel@tonic-gate set .dstable, %g1 ! g1 gets base of table. 3670Sstevel@tonic-gate jmp %g1 + %o1 ! Jump into table 3680Sstevel@tonic-gate nop ! Can't follow CTI by CTI. 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate ENTRY_NP(_fp_write_pdreg) 3710Sstevel@tonic-gate sll %o1, 3, %o1 ! Table entries are 8 bytes each. 3720Sstevel@tonic-gate set .dltable, %g1 ! g1 gets base of table. 3730Sstevel@tonic-gate jmp %g1 + %o1 ! Jump into table 3740Sstevel@tonic-gate nop ! Can't follow CTI by CTI. 3750Sstevel@tonic-gate 3760Sstevel@tonic-gate#define STOREDP(n) jmp %o7+8 ; std %d/**/n, [%o0] 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate.dstable: 3790Sstevel@tonic-gate STOREDP(0) 3800Sstevel@tonic-gate STOREDP(2) 3810Sstevel@tonic-gate STOREDP(4) 3820Sstevel@tonic-gate STOREDP(6) 3830Sstevel@tonic-gate STOREDP(8) 3840Sstevel@tonic-gate STOREDP(10) 3850Sstevel@tonic-gate STOREDP(12) 3860Sstevel@tonic-gate STOREDP(14) 3870Sstevel@tonic-gate STOREDP(16) 3880Sstevel@tonic-gate STOREDP(18) 3890Sstevel@tonic-gate STOREDP(20) 3900Sstevel@tonic-gate STOREDP(22) 3910Sstevel@tonic-gate STOREDP(24) 3920Sstevel@tonic-gate STOREDP(26) 3930Sstevel@tonic-gate STOREDP(28) 3940Sstevel@tonic-gate STOREDP(30) 3950Sstevel@tonic-gate STOREDP(32) 3960Sstevel@tonic-gate STOREDP(34) 3970Sstevel@tonic-gate STOREDP(36) 3980Sstevel@tonic-gate STOREDP(38) 3990Sstevel@tonic-gate STOREDP(40) 4000Sstevel@tonic-gate STOREDP(42) 4010Sstevel@tonic-gate STOREDP(44) 4020Sstevel@tonic-gate STOREDP(46) 4030Sstevel@tonic-gate STOREDP(48) 4040Sstevel@tonic-gate STOREDP(50) 4050Sstevel@tonic-gate STOREDP(52) 4060Sstevel@tonic-gate STOREDP(54) 4070Sstevel@tonic-gate STOREDP(56) 4080Sstevel@tonic-gate STOREDP(58) 4090Sstevel@tonic-gate STOREDP(60) 4100Sstevel@tonic-gate STOREDP(62) 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate#define LOADDP(n) jmp %o7+8 ; ldd [%o0],%d/**/n 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate.dltable: 4150Sstevel@tonic-gate LOADDP(0) 4160Sstevel@tonic-gate LOADDP(2) 4170Sstevel@tonic-gate LOADDP(4) 4180Sstevel@tonic-gate LOADDP(6) 4190Sstevel@tonic-gate LOADDP(8) 4200Sstevel@tonic-gate LOADDP(10) 4210Sstevel@tonic-gate LOADDP(12) 4220Sstevel@tonic-gate LOADDP(14) 4230Sstevel@tonic-gate LOADDP(16) 4240Sstevel@tonic-gate LOADDP(18) 4250Sstevel@tonic-gate LOADDP(20) 4260Sstevel@tonic-gate LOADDP(22) 4270Sstevel@tonic-gate LOADDP(24) 4280Sstevel@tonic-gate LOADDP(26) 4290Sstevel@tonic-gate LOADDP(28) 4300Sstevel@tonic-gate LOADDP(30) 4310Sstevel@tonic-gate LOADDP(32) 4320Sstevel@tonic-gate LOADDP(34) 4330Sstevel@tonic-gate LOADDP(36) 4340Sstevel@tonic-gate LOADDP(38) 4350Sstevel@tonic-gate LOADDP(40) 4360Sstevel@tonic-gate LOADDP(42) 4370Sstevel@tonic-gate LOADDP(44) 4380Sstevel@tonic-gate LOADDP(46) 4390Sstevel@tonic-gate LOADDP(48) 4400Sstevel@tonic-gate LOADDP(50) 4410Sstevel@tonic-gate LOADDP(52) 4420Sstevel@tonic-gate LOADDP(54) 4430Sstevel@tonic-gate LOADDP(56) 4440Sstevel@tonic-gate LOADDP(58) 4450Sstevel@tonic-gate LOADDP(60) 4460Sstevel@tonic-gate LOADDP(62) 4470Sstevel@tonic-gate SET_SIZE(_fp_read_pdreg) 4480Sstevel@tonic-gate SET_SIZE(_fp_write_pdreg) 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate#endif /* lint */ 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate#if defined(lint) || defined(__lint) 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate/*ARGSUSED*/ 4550Sstevel@tonic-gatevoid 4560Sstevel@tonic-gate_fp_write_pfsr(uint64_t *fsr) 4570Sstevel@tonic-gate{} 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate#else /* lint */ 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate ENTRY_NP(_fp_write_pfsr) 4620Sstevel@tonic-gate retl 4630Sstevel@tonic-gate ldx [%o0], %fsr 4640Sstevel@tonic-gate SET_SIZE(_fp_write_pfsr) 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate#endif /* lint */ 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate#if defined(lint) || defined(__lint) 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate/*ARGSUSED*/ 4710Sstevel@tonic-gatevoid 4720Sstevel@tonic-gate_fp_read_pfsr(uint64_t *fsr) 4730Sstevel@tonic-gate{} 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate#else /* lint */ 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate ENTRY_NP(_fp_read_pfsr) 4780Sstevel@tonic-gate retl 4790Sstevel@tonic-gate stx %fsr, [%o0] 4800Sstevel@tonic-gate SET_SIZE(_fp_read_pfsr) 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate#endif /* lint */ 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate#if defined(lint) || defined(__lint) 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate/*ARGSUSED*/ 4870Sstevel@tonic-gatevoid 4880Sstevel@tonic-gate_fp_write_fprs(u_int fprs_val) 4890Sstevel@tonic-gate{} 4900Sstevel@tonic-gate 4910Sstevel@tonic-gate#else /* lint */ 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate ENTRY_NP(_fp_write_fprs) 4940Sstevel@tonic-gate retl 4950Sstevel@tonic-gate wr %o0, %g0, %fprs ! write fprs 4960Sstevel@tonic-gate SET_SIZE(_fp_write_fprs) 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate#endif /* lint */ 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate#if defined(lint) || defined(__lint) 5010Sstevel@tonic-gate 5020Sstevel@tonic-gateunsigned 5030Sstevel@tonic-gate_fp_read_fprs(void) 5040Sstevel@tonic-gate{return 0;} 5050Sstevel@tonic-gate 5060Sstevel@tonic-gate#else /* lint */ 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate ENTRY_NP(_fp_read_fprs) 5090Sstevel@tonic-gate retl 5100Sstevel@tonic-gate rd %fprs, %o0 ! save fprs 5110Sstevel@tonic-gate SET_SIZE(_fp_read_fprs) 5120Sstevel@tonic-gate 5130Sstevel@tonic-gate#endif /* lint */ 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate#if defined(lint) || defined(__lint) 5160Sstevel@tonic-gate 5170Sstevel@tonic-gateunsigned 5180Sstevel@tonic-gate_fp_subcc_ccr(void) 5190Sstevel@tonic-gate{return 0;} 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate#else /* lint */ 5220Sstevel@tonic-gate 5230Sstevel@tonic-gate ENTRY_NP(_fp_subcc_ccr) 5240Sstevel@tonic-gate subcc %o0, %o1, %g0 5250Sstevel@tonic-gate retl 5260Sstevel@tonic-gate rd %ccr, %o0 ! save ccr 5270Sstevel@tonic-gate SET_SIZE(_fp_subcc_ccr) 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate#endif /* lint */ 530*1614Sjb145095 531*1614Sjb145095/* 532*1614Sjb145095 * Floating Point Exceptions handled according to type: 533*1614Sjb145095 * 2) unfinished_fpop 534*1614Sjb145095 * re-execute the faulty instruction(s) using 535*1614Sjb145095 * software emulation (must do every instruction in FQ) 536*1614Sjb145095 * 3) unimplemented_fpop 537*1614Sjb145095 * an unimplemented instruction, if it is legal, 538*1614Sjb145095 * will cause emulation of the instruction (and all 539*1614Sjb145095 * other instuctions in the FQ) 540*1614Sjb145095 * 4) sequence_error 541*1614Sjb145095 * panic, this should not happen, and if it does it 542*1614Sjb145095 * it is the result of a kernel bug 543*1614Sjb145095 * 544*1614Sjb145095 * This code assumes the trap preamble has set up the window environment 545*1614Sjb145095 * for execution of kernel code. 546*1614Sjb145095 * Note: this code could be changed to be part of the cpu-specific 547*1614Sjb145095 * (ie, Spitfire-specific) module code before final release. 548*1614Sjb145095 */ 549*1614Sjb145095 550*1614Sjb145095#if defined(lint) 551*1614Sjb145095 552*1614Sjb145095/* ARGSUSED */ 553*1614Sjb145095void 554*1614Sjb145095_fp_exception(struct regs *rp, uint64_t fsr) 555*1614Sjb145095{} 556*1614Sjb145095 557*1614Sjb145095#else /* lint */ 558*1614Sjb145095 559*1614Sjb145095 ENTRY_NP(_fp_exception) 560*1614Sjb145095 mov %o7, %l0 ! saved return address 561*1614Sjb145095 mov %o0, %l1 ! saved *rp 562*1614Sjb145095 set FSR_FTT, %o4 ! put FSR_FTT in %o4 563*1614Sjb145095 xor %o4, 0xffffffffffffffff, %o3 ! xor FSR_FTT to get 564*1614Sjb145095 and %o1, %o3, %o2 ! an fsr with a zero'd ftt 565*1614Sjb145095 ldn [THREAD_REG + T_LWP], %o3 ! get lwp 566*1614Sjb145095 ldn [%o3 + LWP_FPU], %l3 ! get lwp_fpu 567*1614Sjb145095 stx %o2, [%l3 + FPU_FSR] ! save floating point status 568*1614Sjb145095 and %o1, %o4, %g2 ! get the ftt trap type 569*1614Sjb145095#ifdef DEBUG 570*1614Sjb145095 brnz,a,pt %g2, fttok 571*1614Sjb145095 nop 572*1614Sjb145095 set .badfpfttmsg, %o0 ! panic message 573*1614Sjb145095 call panic ! %o1 has the fsr w/ftt value 574*1614Sjb145095 nop 575*1614Sjb145095fttok: 576*1614Sjb145095#endif /* DEBUG */ 577*1614Sjb145095 srl %g2, FSR_FTT_SHIFT, %o4 ! check ftt 578*1614Sjb145095 cmp %o4, FTT_SEQ ! sanity check for bogus exceptions 579*1614Sjb145095 ! 580*1614Sjb145095 ! traps are already enabled to allow other 581*1614Sjb145095 ! interrupts while emulating floating point instructions 582*1614Sjb145095 ! 583*1614Sjb145095 blt,a,pt %xcc, fpeok 584*1614Sjb145095 nop 585*1614Sjb145095 ! 586*1614Sjb145095 ! Sequence error or unknown ftt exception. 587*1614Sjb145095 ! 588*1614Sjb145095seq_error: 589*1614Sjb145095 set .badfpexcpmsg, %o0 ! panic if bad ftt 590*1614Sjb145095 call panic 591*1614Sjb145095 sra %o4, 0, %o1 ! mov ftt to o1 for panic message 592*1614Sjb145095 593*1614Sjb145095fpeok: 594*1614Sjb145095 call fp_kstat_update ! fp_kstat_update(ftt) 595*1614Sjb145095 mov %o4, %o0 ! ftt 596*1614Sjb145095 ! 597*1614Sjb145095 ! Get the floating point instruction, and run the floating 598*1614Sjb145095 ! point simulator. There is no floating point queue, so we fake one. 599*1614Sjb145095 ! 600*1614Sjb145095 call fp_precise ! fp_precise(®s) 601*1614Sjb145095 mov %l1, %o0 ! saved *rp 602*1614Sjb145095 603*1614Sjb145095fp_ret: 604*1614Sjb145095 rd %fprs, %g1 ! read fprs, save value in %g1 605*1614Sjb145095 st %g1, [%l3 + FPU_FPRS] ! save fprs 606*1614Sjb145095 jmp %l0 + 8 ! jump to saved return address 607*1614Sjb145095 stx %fsr, [%l3 + FPU_FSR] ! save fsr 608*1614Sjb145095 SET_SIZE(_fp_exception) 609*1614Sjb145095 610*1614Sjb145095.badfpexcpmsg: 611*1614Sjb145095 .asciz "unexpected floating point exception %x" 612*1614Sjb145095 613*1614Sjb145095#ifdef DEBUG 614*1614Sjb145095.badfpfttmsg: 615*1614Sjb145095 .asciz "No floating point ftt, fsr %llx" 616*1614Sjb145095#endif /* DEBUG */ 617*1614Sjb145095 618*1614Sjb145095#endif /* lint */ 619*1614Sjb145095 620*1614Sjb145095/* 621*1614Sjb145095 * Floating Point Exceptions. 622*1614Sjb145095 * handled according to type: 623*1614Sjb145095 * 1) IEEE_exception 624*1614Sjb145095 * re-execute the faulty instruction(s) using 625*1614Sjb145095 * software emulation (must do every instruction in FQ) 626*1614Sjb145095 * 627*1614Sjb145095 * This code assumes the trap preamble has set up the window environment 628*1614Sjb145095 * for execution of kernel code. 629*1614Sjb145095 */ 630*1614Sjb145095 631*1614Sjb145095#if defined(lint) 632*1614Sjb145095 633*1614Sjb145095/* ARGSUSED */ 634*1614Sjb145095void 635*1614Sjb145095_fp_ieee_exception(struct regs *rp, uint64_t fsr) 636*1614Sjb145095{} 637*1614Sjb145095 638*1614Sjb145095#else /* lint */ 639*1614Sjb145095 640*1614Sjb145095 ENTRY_NP(_fp_ieee_exception) 641*1614Sjb145095 mov %o7, %l0 ! saved return address 642*1614Sjb145095 mov %o0, %l1 ! saved *rp 643*1614Sjb145095 mov %o1, %l2 ! saved fsr 644*1614Sjb145095 set FSR_FTT, %o4 ! put FSR_FTT in %o4 645*1614Sjb145095 xor %o4, 0xffffffffffffffff, %o3 ! ! xor FSR_FTT to get 646*1614Sjb145095 and %o1, %o3, %o2 ! an fsr with a zero'd ftt 647*1614Sjb145095 ldn [THREAD_REG + T_LWP], %o3 ! get lwp 648*1614Sjb145095 ldn [%o3 + LWP_FPU], %l3 ! get lwp_fpu 649*1614Sjb145095 stx %o2, [%l3 + FPU_FSR] ! save floating point status 650*1614Sjb145095 stub %g0, [%l3 + FPU_QCNT] ! clear fpu_qcnt 651*1614Sjb145095 and %o1, %o4, %g2 ! mask out trap type 652*1614Sjb145095#ifdef DEBUG 653*1614Sjb145095 brnz,a,pt %g2, fttgd 654*1614Sjb145095 nop 655*1614Sjb145095 set .badfpfttmsg, %o0 ! panic message 656*1614Sjb145095 call panic ! %o1 has the fsr w/ftt value 657*1614Sjb145095 nop 658*1614Sjb145095fttgd: 659*1614Sjb145095#endif /* DEBUG */ 660*1614Sjb145095 srl %g2, FSR_FTT_SHIFT, %o4 ! check ftt 661*1614Sjb145095 cmp %o4, FTT_SEQ ! sanity check for bogus exceptions 662*1614Sjb145095 ! 663*1614Sjb145095 ! traps are already enabled to allow other 664*1614Sjb145095 ! interrupts while emulating floating point instructions 665*1614Sjb145095 ! 666*1614Sjb145095 blt,a,pt %xcc, fpegd 667*1614Sjb145095 nop 668*1614Sjb145095 ! 669*1614Sjb145095 ! Sequence error or unknown ftt exception. 670*1614Sjb145095 ! 671*1614Sjb145095seq_err: 672*1614Sjb145095 set .badfpexcpmsg, %o0 ! panic if bad ftt 673*1614Sjb145095 call panic 674*1614Sjb145095 sra %o4, 0, %o1 ! mov ftt to o1 for panic message 675*1614Sjb145095 676*1614Sjb145095fpegd: 677*1614Sjb145095 call fp_kstat_update ! fp_kstat_update(ftt) 678*1614Sjb145095 mov %o4, %o0 ! ftt 679*1614Sjb145095 ! 680*1614Sjb145095 ! Call fpu_trap directly, don't bother to run the fp simulator. 681*1614Sjb145095 ! The *rp is already in %o0. Clear fpu_qcnt. 682*1614Sjb145095 ! 683*1614Sjb145095 set (T_FP_EXCEPTION_IEEE), %o2 ! trap type 684*1614Sjb145095 685*1614Sjb145095 set FSR_CEXC, %o3 686*1614Sjb145095 and %l2, %o3, %g2 ! mask out cexc 687*1614Sjb145095 688*1614Sjb145095 andcc %g2, FSR_CEXC_NX, %g0 ! check for inexact 689*1614Sjb145095 bnz,a,pt %xcc, fpok 690*1614Sjb145095 or %g0, FPE_FLTRES, %o3 ! fp inexact code 691*1614Sjb145095 692*1614Sjb145095 andcc %g2, FSR_CEXC_DZ, %g0 ! check for divide-by-zero 693*1614Sjb145095 bnz,a,pt %xcc, fpok 694*1614Sjb145095 or %g0, FPE_FLTDIV, %o3 ! fp divide by zero code 695*1614Sjb145095 696*1614Sjb145095 andcc %g2, FSR_CEXC_UF, %g0 ! check for underflow 697*1614Sjb145095 bnz,a,pt %xcc, fpok 698*1614Sjb145095 or %g0, FPE_FLTUND, %o3 ! fp underflow code 699*1614Sjb145095 700*1614Sjb145095 andcc %g2, FSR_CEXC_OF, %g0 ! check for overflow 701*1614Sjb145095 bnz,a,pt %xcc, fpok 702*1614Sjb145095 or %g0, FPE_FLTOVF, %o3 ! fp overflow code 703*1614Sjb145095 704*1614Sjb145095 andcc %g2, FSR_CEXC_NV, %g0 ! check for invalid 705*1614Sjb145095 bnz,a,pn %xcc, fpok 706*1614Sjb145095 or %g0, FPE_FLTINV, %o3 ! fp invalid code 707*1614Sjb145095 708*1614Sjb145095cexec_err: 709*1614Sjb145095 set .badfpcexcmsg, %o0 ! panic message 710*1614Sjb145095 call panic ! panic if no cexc bit set 711*1614Sjb145095 mov %g1, %o1 712*1614Sjb145095fpok: 713*1614Sjb145095 mov %l1, %o0 ! saved *rp 714*1614Sjb145095 call fpu_trap ! fpu_trap(®s, addr, type, code) 715*1614Sjb145095 ldn [%o0 + PC_OFF], %o1 ! address of trapping instruction 716*1614Sjb145095 717*1614Sjb145095 rd %fprs, %g1 ! read fprs, save value in %g1 718*1614Sjb145095 st %g1, [%l3 + FPU_FPRS] ! save fprs 719*1614Sjb145095 jmp %l0 + 8 ! jump to saved return address 720*1614Sjb145095 stx %fsr, [%l3 + FPU_FSR] ! save fsr 721*1614Sjb145095 SET_SIZE(_fp_ieee_exception) 722*1614Sjb145095 723*1614Sjb145095.badfpcexcmsg: 724*1614Sjb145095 .asciz "No floating point exception, fsr %llx" 725*1614Sjb145095 726*1614Sjb145095#endif /* lint */ 727