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_aux.c (5508B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*---------------------------------------------------------------------------+
      3 |  fpu_aux.c                                                                |
      4 |                                                                           |
      5 | Code to implement some of the FPU auxiliary instructions.                 |
      6 |                                                                           |
      7 | Copyright (C) 1992,1993,1994,1997                                         |
      8 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
      9 |                  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 "control_w.h"
     19
     20static void fnop(void)
     21{
     22}
     23
     24static void fclex(void)
     25{
     26	partial_status &=
     27	    ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
     28	      SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
     29	      SW_Invalid);
     30	no_ip_update = 1;
     31}
     32
     33/* Needs to be externally visible */
     34void fpstate_init_soft(struct swregs_state *soft)
     35{
     36	struct address *oaddr, *iaddr;
     37	memset(soft, 0, sizeof(*soft));
     38	soft->cwd = 0x037f;
     39	soft->swd = 0;
     40	soft->ftop = 0;	/* We don't keep top in the status word internally. */
     41	soft->twd = 0xffff;
     42	/* The behaviour is different from that detailed in
     43	   Section 15.1.6 of the Intel manual */
     44	oaddr = (struct address *)&soft->foo;
     45	oaddr->offset = 0;
     46	oaddr->selector = 0;
     47	iaddr = (struct address *)&soft->fip;
     48	iaddr->offset = 0;
     49	iaddr->selector = 0;
     50	iaddr->opcode = 0;
     51	soft->no_update = 1;
     52}
     53
     54void finit(void)
     55{
     56	fpstate_init_soft(&current->thread.fpu.fpstate->regs.soft);
     57}
     58
     59/*
     60 * These are nops on the i387..
     61 */
     62#define feni fnop
     63#define fdisi fnop
     64#define fsetpm fnop
     65
     66static FUNC const finit_table[] = {
     67	feni, fdisi, fclex, finit,
     68	fsetpm, FPU_illegal, FPU_illegal, FPU_illegal
     69};
     70
     71void finit_(void)
     72{
     73	(finit_table[FPU_rm]) ();
     74}
     75
     76static void fstsw_ax(void)
     77{
     78	*(short *)&FPU_EAX = status_word();
     79	no_ip_update = 1;
     80}
     81
     82static FUNC const fstsw_table[] = {
     83	fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal,
     84	FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
     85};
     86
     87void fstsw_(void)
     88{
     89	(fstsw_table[FPU_rm]) ();
     90}
     91
     92static FUNC const fp_nop_table[] = {
     93	fnop, FPU_illegal, FPU_illegal, FPU_illegal,
     94	FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal
     95};
     96
     97void fp_nop(void)
     98{
     99	(fp_nop_table[FPU_rm]) ();
    100}
    101
    102void fld_i_(void)
    103{
    104	FPU_REG *st_new_ptr;
    105	int i;
    106	u_char tag;
    107
    108	if (STACK_OVERFLOW) {
    109		FPU_stack_overflow();
    110		return;
    111	}
    112
    113	/* fld st(i) */
    114	i = FPU_rm;
    115	if (NOT_EMPTY(i)) {
    116		reg_copy(&st(i), st_new_ptr);
    117		tag = FPU_gettagi(i);
    118		push();
    119		FPU_settag0(tag);
    120	} else {
    121		if (control_word & CW_Invalid) {
    122			/* The masked response */
    123			FPU_stack_underflow();
    124		} else
    125			EXCEPTION(EX_StackUnder);
    126	}
    127
    128}
    129
    130void fxch_i(void)
    131{
    132	/* fxch st(i) */
    133	FPU_REG t;
    134	int i = FPU_rm;
    135	FPU_REG *st0_ptr = &st(0), *sti_ptr = &st(i);
    136	long tag_word = fpu_tag_word;
    137	int regnr = top & 7, regnri = ((regnr + i) & 7);
    138	u_char st0_tag = (tag_word >> (regnr * 2)) & 3;
    139	u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
    140
    141	if (st0_tag == TAG_Empty) {
    142		if (sti_tag == TAG_Empty) {
    143			FPU_stack_underflow();
    144			FPU_stack_underflow_i(i);
    145			return;
    146		}
    147		if (control_word & CW_Invalid) {
    148			/* Masked response */
    149			FPU_copy_to_reg0(sti_ptr, sti_tag);
    150		}
    151		FPU_stack_underflow_i(i);
    152		return;
    153	}
    154	if (sti_tag == TAG_Empty) {
    155		if (control_word & CW_Invalid) {
    156			/* Masked response */
    157			FPU_copy_to_regi(st0_ptr, st0_tag, i);
    158		}
    159		FPU_stack_underflow();
    160		return;
    161	}
    162	clear_C1();
    163
    164	reg_copy(st0_ptr, &t);
    165	reg_copy(sti_ptr, st0_ptr);
    166	reg_copy(&t, sti_ptr);
    167
    168	tag_word &= ~(3 << (regnr * 2)) & ~(3 << (regnri * 2));
    169	tag_word |= (sti_tag << (regnr * 2)) | (st0_tag << (regnri * 2));
    170	fpu_tag_word = tag_word;
    171}
    172
    173static void fcmovCC(void)
    174{
    175	/* fcmovCC st(i) */
    176	int i = FPU_rm;
    177	FPU_REG *st0_ptr = &st(0);
    178	FPU_REG *sti_ptr = &st(i);
    179	long tag_word = fpu_tag_word;
    180	int regnr = top & 7;
    181	int regnri = (top + i) & 7;
    182	u_char sti_tag = (tag_word >> (regnri * 2)) & 3;
    183
    184	if (sti_tag == TAG_Empty) {
    185		FPU_stack_underflow();
    186		clear_C1();
    187		return;
    188	}
    189	reg_copy(sti_ptr, st0_ptr);
    190	tag_word &= ~(3 << (regnr * 2));
    191	tag_word |= (sti_tag << (regnr * 2));
    192	fpu_tag_word = tag_word;
    193}
    194
    195void fcmovb(void)
    196{
    197	if (FPU_EFLAGS & X86_EFLAGS_CF)
    198		fcmovCC();
    199}
    200
    201void fcmove(void)
    202{
    203	if (FPU_EFLAGS & X86_EFLAGS_ZF)
    204		fcmovCC();
    205}
    206
    207void fcmovbe(void)
    208{
    209	if (FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF))
    210		fcmovCC();
    211}
    212
    213void fcmovu(void)
    214{
    215	if (FPU_EFLAGS & X86_EFLAGS_PF)
    216		fcmovCC();
    217}
    218
    219void fcmovnb(void)
    220{
    221	if (!(FPU_EFLAGS & X86_EFLAGS_CF))
    222		fcmovCC();
    223}
    224
    225void fcmovne(void)
    226{
    227	if (!(FPU_EFLAGS & X86_EFLAGS_ZF))
    228		fcmovCC();
    229}
    230
    231void fcmovnbe(void)
    232{
    233	if (!(FPU_EFLAGS & (X86_EFLAGS_CF|X86_EFLAGS_ZF)))
    234		fcmovCC();
    235}
    236
    237void fcmovnu(void)
    238{
    239	if (!(FPU_EFLAGS & X86_EFLAGS_PF))
    240		fcmovCC();
    241}
    242
    243void ffree_(void)
    244{
    245	/* ffree st(i) */
    246	FPU_settagi(FPU_rm, TAG_Empty);
    247}
    248
    249void ffreep(void)
    250{
    251	/* ffree st(i) + pop - unofficial code */
    252	FPU_settagi(FPU_rm, TAG_Empty);
    253	FPU_pop();
    254}
    255
    256void fst_i_(void)
    257{
    258	/* fst st(i) */
    259	FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
    260}
    261
    262void fstp_i(void)
    263{
    264	/* fstp st(i) */
    265	FPU_copy_to_regi(&st(0), FPU_gettag0(), FPU_rm);
    266	FPU_pop();
    267}