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

test_FCOMI.c (7391B)


      1// SPDX-License-Identifier: GPL-2.0
      2#undef _GNU_SOURCE
      3#define _GNU_SOURCE 1
      4#undef __USE_GNU
      5#define __USE_GNU 1
      6#include <unistd.h>
      7#include <stdlib.h>
      8#include <string.h>
      9#include <stdio.h>
     10#include <signal.h>
     11#include <sys/types.h>
     12#include <sys/select.h>
     13#include <sys/time.h>
     14#include <sys/wait.h>
     15#include <fenv.h>
     16
     17enum {
     18	CF = 1 << 0,
     19	PF = 1 << 2,
     20	ZF = 1 << 6,
     21	ARITH = CF | PF | ZF,
     22};
     23
     24long res_fcomi_pi_1;
     25long res_fcomi_1_pi;
     26long res_fcomi_1_1;
     27long res_fcomi_nan_1;
     28/* sNaN is s|111 1111 1|1xx xxxx xxxx xxxx xxxx xxxx */
     29/* qNaN is s|111 1111 1|0xx xxxx xxxx xxxx xxxx xxxx (some x must be nonzero) */
     30int snan = 0x7fc11111;
     31int qnan = 0x7f811111;
     32unsigned short snan1[5];
     33/* sNaN80 is s|111 1111 1111 1111 |10xx xx...xx (some x must be nonzero) */
     34unsigned short snan80[5] = { 0x1111, 0x1111, 0x1111, 0x8111, 0x7fff };
     35
     36int test(long flags)
     37{
     38	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
     39
     40	asm ("\n"
     41
     42	"	push	%0""\n"
     43	"	popf""\n"
     44	"	fld1""\n"
     45	"	fldpi""\n"
     46	"	fcomi	%%st(1), %%st" "\n"
     47	"	ffree	%%st(0)" "\n"
     48	"	ffree	%%st(1)" "\n"
     49	"	pushf""\n"
     50	"	pop	res_fcomi_1_pi""\n"
     51
     52	"	push	%0""\n"
     53	"	popf""\n"
     54	"	fldpi""\n"
     55	"	fld1""\n"
     56	"	fcomi	%%st(1), %%st" "\n"
     57	"	ffree	%%st(0)" "\n"
     58	"	ffree	%%st(1)" "\n"
     59	"	pushf""\n"
     60	"	pop	res_fcomi_pi_1""\n"
     61
     62	"	push	%0""\n"
     63	"	popf""\n"
     64	"	fld1""\n"
     65	"	fld1""\n"
     66	"	fcomi	%%st(1), %%st" "\n"
     67	"	ffree	%%st(0)" "\n"
     68	"	ffree	%%st(1)" "\n"
     69	"	pushf""\n"
     70	"	pop	res_fcomi_1_1""\n"
     71	:
     72	: "r" (flags)
     73	);
     74	if ((res_fcomi_1_pi & ARITH) != (0)) {
     75		printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
     76		return 1;
     77	}
     78	if ((res_fcomi_pi_1 & ARITH) != (CF)) {
     79		printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
     80		return 1;
     81	}
     82	if ((res_fcomi_1_1 & ARITH) != (ZF)) {
     83		printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
     84		return 1;
     85	}
     86	if (fetestexcept(FE_INVALID) != 0) {
     87		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
     88		return 1;
     89	}
     90	return 0;
     91}
     92
     93int test_qnan(long flags)
     94{
     95	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
     96
     97	asm ("\n"
     98	"	push	%0""\n"
     99	"	popf""\n"
    100	"	flds	qnan""\n"
    101	"	fld1""\n"
    102	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
    103	"	fcomi	%%st(1), %%st" "\n"
    104	"	ffree	%%st(0)" "\n"
    105	"	ffree	%%st(1)" "\n"
    106	"	pushf""\n"
    107	"	pop	res_fcomi_nan_1""\n"
    108	:
    109	: "r" (flags)
    110	);
    111	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
    112		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
    113		return 1;
    114	}
    115	if (fetestexcept(FE_INVALID) != FE_INVALID) {
    116		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
    117		return 1;
    118	}
    119	return 0;
    120}
    121
    122int testu_qnan(long flags)
    123{
    124	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
    125
    126	asm ("\n"
    127	"	push	%0""\n"
    128	"	popf""\n"
    129	"	flds	qnan""\n"
    130	"	fld1""\n"
    131	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
    132	"	fucomi	%%st(1), %%st" "\n"
    133	"	ffree	%%st(0)" "\n"
    134	"	ffree	%%st(1)" "\n"
    135	"	pushf""\n"
    136	"	pop	res_fcomi_nan_1""\n"
    137	:
    138	: "r" (flags)
    139	);
    140	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
    141		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
    142		return 1;
    143	}
    144	if (fetestexcept(FE_INVALID) != 0) {
    145		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
    146		return 1;
    147	}
    148	return 0;
    149}
    150
    151int testu_snan(long flags)
    152{
    153	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
    154
    155	asm ("\n"
    156	"	push	%0""\n"
    157	"	popf""\n"
    158//	"	flds	snan""\n"	// WRONG, this will convert 32-bit fp snan to a *qnan* in 80-bit fp register!
    159//	"	fstpt	snan1""\n"	// if uncommented, it prints "snan1:7fff c111 1100 0000 0000" - c111, not 8111!
    160//	"	fnclex""\n"		// flds of a snan raised FE_INVALID, clear it
    161	"	fldt	snan80""\n"	// fldt never raise FE_INVALID
    162	"	fld1""\n"
    163	"	fucomi	%%st(1), %%st" "\n"
    164	"	ffree	%%st(0)" "\n"
    165	"	ffree	%%st(1)" "\n"
    166	"	pushf""\n"
    167	"	pop	res_fcomi_nan_1""\n"
    168	:
    169	: "r" (flags)
    170	);
    171	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
    172		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
    173		return 1;
    174	}
    175//	printf("snan:%x snan1:%04x %04x %04x %04x %04x\n", snan, snan1[4], snan1[3], snan1[2], snan1[1], snan1[0]);
    176	if (fetestexcept(FE_INVALID) != FE_INVALID) {
    177		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
    178		return 1;
    179	}
    180	return 0;
    181}
    182
    183int testp(long flags)
    184{
    185	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
    186
    187	asm ("\n"
    188
    189	"	push	%0""\n"
    190	"	popf""\n"
    191	"	fld1""\n"
    192	"	fldpi""\n"
    193	"	fcomip	%%st(1), %%st" "\n"
    194	"	ffree	%%st(0)" "\n"
    195	"	pushf""\n"
    196	"	pop	res_fcomi_1_pi""\n"
    197
    198	"	push	%0""\n"
    199	"	popf""\n"
    200	"	fldpi""\n"
    201	"	fld1""\n"
    202	"	fcomip	%%st(1), %%st" "\n"
    203	"	ffree	%%st(0)" "\n"
    204	"	pushf""\n"
    205	"	pop	res_fcomi_pi_1""\n"
    206
    207	"	push	%0""\n"
    208	"	popf""\n"
    209	"	fld1""\n"
    210	"	fld1""\n"
    211	"	fcomip	%%st(1), %%st" "\n"
    212	"	ffree	%%st(0)" "\n"
    213	"	pushf""\n"
    214	"	pop	res_fcomi_1_1""\n"
    215	:
    216	: "r" (flags)
    217	);
    218	if ((res_fcomi_1_pi & ARITH) != (0)) {
    219		printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
    220		return 1;
    221	}
    222	if ((res_fcomi_pi_1 & ARITH) != (CF)) {
    223		printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
    224		return 1;
    225	}
    226	if ((res_fcomi_1_1 & ARITH) != (ZF)) {
    227		printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
    228		return 1;
    229	}
    230	if (fetestexcept(FE_INVALID) != 0) {
    231		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
    232		return 1;
    233	}
    234	return 0;
    235}
    236
    237int testp_qnan(long flags)
    238{
    239	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
    240
    241	asm ("\n"
    242	"	push	%0""\n"
    243	"	popf""\n"
    244	"	flds	qnan""\n"
    245	"	fld1""\n"
    246	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
    247	"	fcomip	%%st(1), %%st" "\n"
    248	"	ffree	%%st(0)" "\n"
    249	"	pushf""\n"
    250	"	pop	res_fcomi_nan_1""\n"
    251	:
    252	: "r" (flags)
    253	);
    254	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
    255		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
    256		return 1;
    257	}
    258	if (fetestexcept(FE_INVALID) != FE_INVALID) {
    259		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
    260		return 1;
    261	}
    262	return 0;
    263}
    264
    265int testup_qnan(long flags)
    266{
    267	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);
    268
    269	asm ("\n"
    270	"	push	%0""\n"
    271	"	popf""\n"
    272	"	flds	qnan""\n"
    273	"	fld1""\n"
    274	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
    275	"	fucomip	%%st(1), %%st" "\n"
    276	"	ffree	%%st(0)" "\n"
    277	"	pushf""\n"
    278	"	pop	res_fcomi_nan_1""\n"
    279	:
    280	: "r" (flags)
    281	);
    282	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
    283		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
    284		return 1;
    285	}
    286	if (fetestexcept(FE_INVALID) != 0) {
    287		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
    288		return 1;
    289	}
    290	return 0;
    291}
    292
    293void sighandler(int sig)
    294{
    295	printf("[FAIL]\tGot signal %d, exiting\n", sig);
    296	exit(1);
    297}
    298
    299int main(int argc, char **argv, char **envp)
    300{
    301	int err = 0;
    302
    303	/* SIGILL triggers on 32-bit kernels w/o fcomi emulation
    304	 * when run with "no387 nofxsr". Other signals are caught
    305	 * just in case.
    306	 */
    307	signal(SIGILL, sighandler);
    308	signal(SIGFPE, sighandler);
    309	signal(SIGSEGV, sighandler);
    310
    311	printf("[RUN]\tTesting f[u]comi[p] instructions\n");
    312	err |= test(0);
    313	err |= test_qnan(0);
    314	err |= testu_qnan(0);
    315	err |= testu_snan(0);
    316	err |= test(CF|ZF|PF);
    317	err |= test_qnan(CF|ZF|PF);
    318	err |= testu_qnan(CF|ZF|PF);
    319	err |= testu_snan(CF|ZF|PF);
    320	err |= testp(0);
    321	err |= testp_qnan(0);
    322	err |= testup_qnan(0);
    323	err |= testp(CF|ZF|PF);
    324	err |= testp_qnan(CF|ZF|PF);
    325	err |= testup_qnan(CF|ZF|PF);
    326	if (!err)
    327		printf("[OK]\tf[u]comi[p]\n");
    328	else
    329		printf("[FAIL]\tf[u]comi[p] errors: %d\n", err);
    330
    331	return err;
    332}