cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

decode_exc.c (10943B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Linux/PA-RISC Project (http://www.parisc-linux.org/)
      4 *
      5 * Floating-point emulation code
      6 *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
      7 */
      8/*
      9 * BEGIN_DESC
     10 *
     11 *  File:
     12 *	@(#)	pa/fp/decode_exc.c		$ Revision: $
     13 *
     14 *  Purpose:
     15 *	<<please update with a synopsis of the functionality provided by this file>>
     16 *
     17 *  External Interfaces:
     18 *	<<the following list was autogenerated, please review>>
     19 *	decode_fpu(Fpu_register, trap_counts)
     20 *
     21 *  Internal Interfaces:
     22 *	<<please update>>
     23 *
     24 *  Theory:
     25 *	<<please update with a overview of the operation of this file>>
     26 *
     27 * END_DESC
     28*/
     29
     30#include <linux/kernel.h>
     31#include "float.h"
     32#include "sgl_float.h"
     33#include "dbl_float.h"
     34#include "cnv_float.h"
     35/* #include "types.h" */
     36#include <asm/signal.h>
     37#include <asm/siginfo.h>
     38/* #include <machine/sys/mdep_private.h> */
     39
     40#undef Fpustatus_register
     41#define Fpustatus_register Fpu_register[0]
     42
     43/* General definitions */
     44#define DOESTRAP 1
     45#define NOTRAP 0
     46#define SIGNALCODE(signal, code) ((signal) << 24 | (code))
     47#define copropbit	1<<31-2	/* bit position 2 */
     48#define opclass		9	/* bits 21 & 22 */
     49#define fmtbits		11	/* bits 19 & 20 */
     50#define df		13	/* bits 17 & 18 */
     51#define twobits		3	/* mask low-order 2 bits */
     52#define fivebits	31	/* mask low-order 5 bits */
     53#define MAX_EXCP_REG	7	/* number of excpeption registers to check */
     54
     55/* Exception register definitions */
     56#define Excp_type(index) Exceptiontype(Fpu_register[index])
     57#define Excp_instr(index) Instructionfield(Fpu_register[index])
     58#define Clear_excp_register(index) Allexception(Fpu_register[index]) = 0
     59#define Excp_format() \
     60	(current_ir >> ((current_ir>>opclass & twobits) == 1 ? df : fmtbits) & twobits)
     61
     62/* Miscellaneous definitions */
     63#define Fpu_sgl(index) Fpu_register[index*2]
     64
     65#define Fpu_dblp1(index) Fpu_register[index*2]
     66#define Fpu_dblp2(index) Fpu_register[(index*2)+1]
     67
     68#define Fpu_quadp1(index) Fpu_register[index*2]
     69#define Fpu_quadp2(index) Fpu_register[(index*2)+1]
     70#define Fpu_quadp3(index) Fpu_register[(index*2)+2]
     71#define Fpu_quadp4(index) Fpu_register[(index*2)+3]
     72
     73/* Single precision floating-point definitions */
     74#ifndef Sgl_decrement
     75# define Sgl_decrement(sgl_value) Sall(sgl_value)--
     76#endif
     77
     78/* Double precision floating-point definitions */
     79#ifndef Dbl_decrement
     80# define Dbl_decrement(dbl_valuep1,dbl_valuep2) \
     81    if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)-- 
     82#endif
     83
     84
     85#define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) {	\
     86	aflags=(Fpu_register[0])>>27;	/* assumes zero fill. 32 bit */	\
     87	Fpu_register[0] |= bflags;					\
     88}
     89
     90u_int
     91decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
     92{
     93    unsigned int current_ir, excp;
     94    int target, exception_index = 1;
     95    boolean inexact;
     96    unsigned int aflags;
     97    unsigned int bflags;
     98    unsigned int excptype;
     99
    100
    101    /* Keep stats on how many floating point exceptions (based on type)
    102     * that happen.  Want to keep this overhead low, but still provide
    103     * some information to the customer.  All exits from this routine
    104     * need to restore Fpu_register[0]
    105     */
    106
    107    bflags=(Fpu_register[0] & 0xf8000000);
    108    Fpu_register[0] &= 0x07ffffff;
    109
    110    /* exception_index is used to index the exception register queue.  It
    111     *   always points at the last register that contains a valid exception.  A
    112     *   zero value implies no exceptions (also the initialized value).  Setting
    113     *   the T-bit resets the exception_index to zero.
    114     */
    115
    116    /*
    117     * Check for reserved-op exception.  A reserved-op exception does not 
    118     * set any exception registers nor does it set the T-bit.  If the T-bit
    119     * is not set then a reserved-op exception occurred.
    120     *
    121     * At some point, we may want to report reserved op exceptions as
    122     * illegal instructions.
    123     */
    124    
    125    if (!Is_tbit_set()) {
    126	update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
    127	return SIGNALCODE(SIGILL, ILL_COPROC);
    128    }
    129
    130    /* 
    131     * Is a coprocessor op. 
    132     *
    133     * Now we need to determine what type of exception occurred.
    134     */
    135    for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) {
    136	current_ir = Excp_instr(exception_index);
    137	  /*
    138	   * On PA89: there are 5 different unimplemented exception
    139	   * codes: 0x1, 0x9, 0xb, 0x3, and 0x23.  PA-RISC 2.0 adds
    140	   * another, 0x2b.  Only these have the low order bit set.
    141	   */
    142	excptype = Excp_type(exception_index);
    143	if (excptype & UNIMPLEMENTEDEXCEPTION) {
    144		/*
    145		 * Clear T-bit and exception register so that
    146		 * we can tell if a trap really occurs while 
    147		 * emulating the instruction.
    148		 */
    149		Clear_tbit();
    150		Clear_excp_register(exception_index);
    151		/*
    152		 * Now emulate this instruction.  If a trap occurs,
    153		 * fpudispatch will return a non-zero number 
    154		 */
    155		excp = fpudispatch(current_ir,excptype,0,Fpu_register);
    156		/* accumulate the status flags, don't lose them as in hpux */
    157		if (excp) {
    158			/*
    159			 * We now need to make sure that the T-bit and the
    160			 * exception register contain the correct values
    161			 * before continuing.
    162			 */
    163			/*
    164			 * Set t-bit since it might still be needed for a
    165			 * subsequent real trap (I don't understand fully -PB)
    166			 */
    167			Set_tbit();
    168			/* some of the following code uses
    169			 * Excp_type(exception_index) so fix that up */
    170			Set_exceptiontype_and_instr_field(excp,current_ir,
    171			 Fpu_register[exception_index]);
    172			if (excp == UNIMPLEMENTEDEXCEPTION) {
    173				/*
    174			 	 * it is really unimplemented, so restore the
    175			 	 * TIMEX extended unimplemented exception code
    176			 	 */
    177				excp = excptype;
    178				update_trap_counts(Fpu_register, aflags, bflags, 
    179					   trap_counts);
    180				return SIGNALCODE(SIGILL, ILL_COPROC);
    181			}
    182			/* some of the following code uses excptype, so
    183			 * fix that up too */
    184			excptype = excp;
    185		}
    186		/* handle exceptions other than the real UNIMPLIMENTED the
    187		 * same way as if the hardware had caused them */
    188		if (excp == NOEXCEPTION)
    189			/* For now use 'break', should technically be 'continue' */
    190			break;
    191	}
    192
    193	  /*
    194	   * In PA89, the underflow exception has been extended to encode
    195	   * additional information.  The exception looks like pp01x0,
    196	   * where x is 1 if inexact and pp represent the inexact bit (I)
    197	   * and the round away bit (RA)
    198	   */
    199	if (excptype & UNDERFLOWEXCEPTION) {
    200		/* check for underflow trap enabled */
    201		if (Is_underflowtrap_enabled()) {
    202			update_trap_counts(Fpu_register, aflags, bflags, 
    203					   trap_counts);
    204			return SIGNALCODE(SIGFPE, FPE_FLTUND);
    205		} else {
    206		    /*
    207		     * Isn't a real trap; we need to 
    208		     * return the default value.
    209		     */
    210		    target = current_ir & fivebits;
    211#ifndef lint
    212		    if (Ibit(Fpu_register[exception_index])) inexact = TRUE;
    213		    else inexact = FALSE;
    214#endif
    215		    switch (Excp_format()) {
    216		      case SGL:
    217		        /*
    218		         * If ra (round-away) is set, will 
    219		         * want to undo the rounding done
    220		         * by the hardware.
    221		         */
    222		        if (Rabit(Fpu_register[exception_index])) 
    223				Sgl_decrement(Fpu_sgl(target));
    224
    225			/* now denormalize */
    226			sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode());
    227		    	break;
    228		      case DBL:
    229		    	/*
    230		    	 * If ra (round-away) is set, will 
    231		    	 * want to undo the rounding done
    232		    	 * by the hardware.
    233		    	 */
    234		    	if (Rabit(Fpu_register[exception_index])) 
    235				Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target));
    236
    237			/* now denormalize */
    238			dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target),
    239			  &inexact,Rounding_mode());
    240		    	break;
    241		    }
    242		    if (inexact) Set_underflowflag();
    243		    /* 
    244		     * Underflow can generate an inexact
    245		     * exception.  If inexact trap is enabled,
    246		     * want to do an inexact trap, otherwise 
    247		     * set inexact flag.
    248		     */
    249		    if (inexact && Is_inexacttrap_enabled()) {
    250		    	/*
    251		    	 * Set exception field of exception register
    252		    	 * to inexact, parm field to zero.
    253			 * Underflow bit should be cleared.
    254		    	 */
    255		    	Set_exceptiontype(Fpu_register[exception_index],
    256			 INEXACTEXCEPTION);
    257			Set_parmfield(Fpu_register[exception_index],0);
    258			update_trap_counts(Fpu_register, aflags, bflags, 
    259					   trap_counts);
    260			return SIGNALCODE(SIGFPE, FPE_FLTRES);
    261		    }
    262		    else {
    263		    	/*
    264		    	 * Exception register needs to be cleared.  
    265			 * Inexact flag needs to be set if inexact.
    266		    	 */
    267		    	Clear_excp_register(exception_index);
    268		    	if (inexact) Set_inexactflag();
    269		    }
    270		}
    271		continue;
    272	}
    273	switch(Excp_type(exception_index)) {
    274	  case OVERFLOWEXCEPTION:
    275	  case OVERFLOWEXCEPTION | INEXACTEXCEPTION:
    276		/* check for overflow trap enabled */
    277			update_trap_counts(Fpu_register, aflags, bflags, 
    278					   trap_counts);
    279		if (Is_overflowtrap_enabled()) {
    280			update_trap_counts(Fpu_register, aflags, bflags, 
    281					   trap_counts);
    282			return SIGNALCODE(SIGFPE, FPE_FLTOVF);
    283		} else {
    284			/*
    285			 * Isn't a real trap; we need to 
    286			 * return the default value.
    287			 */
    288			target = current_ir & fivebits;
    289			switch (Excp_format()) {
    290			  case SGL: 
    291				Sgl_setoverflow(Fpu_sgl(target));
    292				break;
    293			  case DBL:
    294				Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target));
    295				break;
    296			}
    297			Set_overflowflag();
    298			/* 
    299			 * Overflow always generates an inexact
    300			 * exception.  If inexact trap is enabled,
    301			 * want to do an inexact trap, otherwise 
    302			 * set inexact flag.
    303			 */
    304			if (Is_inexacttrap_enabled()) {
    305				/*
    306				 * Set exception field of exception
    307				 * register to inexact.  Overflow
    308				 * bit should be cleared.
    309				 */
    310				Set_exceptiontype(Fpu_register[exception_index],
    311				 INEXACTEXCEPTION);
    312				update_trap_counts(Fpu_register, aflags, bflags,
    313					   trap_counts);
    314				return SIGNALCODE(SIGFPE, FPE_FLTRES);
    315			}
    316			else {
    317				/*
    318				 * Exception register needs to be cleared.  
    319				 * Inexact flag needs to be set.
    320				 */
    321				Clear_excp_register(exception_index);
    322				Set_inexactflag();
    323			}
    324		}
    325		break;
    326	  case INVALIDEXCEPTION:
    327	  case OPC_2E_INVALIDEXCEPTION:
    328		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
    329		return SIGNALCODE(SIGFPE, FPE_FLTINV);
    330	  case DIVISIONBYZEROEXCEPTION:
    331		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
    332		Clear_excp_register(exception_index);
    333	  	return SIGNALCODE(SIGFPE, FPE_FLTDIV);
    334	  case INEXACTEXCEPTION:
    335		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
    336		return SIGNALCODE(SIGFPE, FPE_FLTRES);
    337	  default:
    338		update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
    339		printk("%s(%d) Unknown FPU exception 0x%x\n", __FILE__,
    340			__LINE__, Excp_type(exception_index));
    341		return SIGNALCODE(SIGILL, ILL_COPROC);
    342	  case NOEXCEPTION:	/* no exception */
    343		/*
    344		 * Clear exception register in case 
    345		 * other fields are non-zero.
    346		 */
    347		Clear_excp_register(exception_index);
    348		break;
    349	}
    350    }
    351    /*
    352     * No real exceptions occurred.
    353     */
    354    Clear_tbit();
    355    update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
    356    return(NOTRAP);
    357}