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

fpu_etc.c (3192B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*---------------------------------------------------------------------------+
      3 |  fpu_etc.c                                                                |
      4 |                                                                           |
      5 | Implement a few FPU instructions.                                         |
      6 |                                                                           |
      7 | Copyright (C) 1992,1993,1994,1997                                         |
      8 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
      9 |                       Australia.  E-mail   billm@suburbia.net             |
     10 |                                                                           |
     11 |                                                                           |
     12 +---------------------------------------------------------------------------*/
     13
     14#include "fpu_system.h"
     15#include "exception.h"
     16#include "fpu_emu.h"
     17#include "status_w.h"
     18#include "reg_constant.h"
     19
     20static void fchs(FPU_REG *st0_ptr, u_char st0tag)
     21{
     22	if (st0tag ^ TAG_Empty) {
     23		signbyte(st0_ptr) ^= SIGN_NEG;
     24		clear_C1();
     25	} else
     26		FPU_stack_underflow();
     27}
     28
     29static void fabs(FPU_REG *st0_ptr, u_char st0tag)
     30{
     31	if (st0tag ^ TAG_Empty) {
     32		setpositive(st0_ptr);
     33		clear_C1();
     34	} else
     35		FPU_stack_underflow();
     36}
     37
     38static void ftst_(FPU_REG *st0_ptr, u_char st0tag)
     39{
     40	switch (st0tag) {
     41	case TAG_Zero:
     42		setcc(SW_C3);
     43		break;
     44	case TAG_Valid:
     45		if (getsign(st0_ptr) == SIGN_POS)
     46			setcc(0);
     47		else
     48			setcc(SW_C0);
     49		break;
     50	case TAG_Special:
     51		switch (FPU_Special(st0_ptr)) {
     52		case TW_Denormal:
     53			if (getsign(st0_ptr) == SIGN_POS)
     54				setcc(0);
     55			else
     56				setcc(SW_C0);
     57			if (denormal_operand() < 0) {
     58#ifdef PECULIAR_486
     59				/* This is weird! */
     60				if (getsign(st0_ptr) == SIGN_POS)
     61					setcc(SW_C3);
     62#endif /* PECULIAR_486 */
     63				return;
     64			}
     65			break;
     66		case TW_NaN:
     67			setcc(SW_C0 | SW_C2 | SW_C3);	/* Operand is not comparable */
     68			EXCEPTION(EX_Invalid);
     69			break;
     70		case TW_Infinity:
     71			if (getsign(st0_ptr) == SIGN_POS)
     72				setcc(0);
     73			else
     74				setcc(SW_C0);
     75			break;
     76		default:
     77			setcc(SW_C0 | SW_C2 | SW_C3);	/* Operand is not comparable */
     78			EXCEPTION(EX_INTERNAL | 0x14);
     79			break;
     80		}
     81		break;
     82	case TAG_Empty:
     83		setcc(SW_C0 | SW_C2 | SW_C3);
     84		EXCEPTION(EX_StackUnder);
     85		break;
     86	}
     87}
     88
     89static void fxam(FPU_REG *st0_ptr, u_char st0tag)
     90{
     91	int c = 0;
     92	switch (st0tag) {
     93	case TAG_Empty:
     94		c = SW_C3 | SW_C0;
     95		break;
     96	case TAG_Zero:
     97		c = SW_C3;
     98		break;
     99	case TAG_Valid:
    100		c = SW_C2;
    101		break;
    102	case TAG_Special:
    103		switch (FPU_Special(st0_ptr)) {
    104		case TW_Denormal:
    105			c = SW_C2 | SW_C3;	/* Denormal */
    106			break;
    107		case TW_NaN:
    108			/* We also use NaN for unsupported types. */
    109			if ((st0_ptr->sigh & 0x80000000)
    110			    && (exponent(st0_ptr) == EXP_OVER))
    111				c = SW_C0;
    112			break;
    113		case TW_Infinity:
    114			c = SW_C2 | SW_C0;
    115			break;
    116		}
    117	}
    118	if (getsign(st0_ptr) == SIGN_NEG)
    119		c |= SW_C1;
    120	setcc(c);
    121}
    122
    123static FUNC_ST0 const fp_etc_table[] = {
    124	fchs, fabs, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal,
    125	ftst_, fxam, (FUNC_ST0) FPU_illegal, (FUNC_ST0) FPU_illegal
    126};
    127
    128void FPU_etc(void)
    129{
    130	(fp_etc_table[FPU_rm]) (&st(0), FPU_gettag0());
    131}