All of lore.kernel.org
 help / color / mirror / Atom feed
From: Denys Vlasenko <dvlasenk@redhat.com>
To: Ingo Molnar <mingo@kernel.org>
Cc: Denys Vlasenko <dvlasenk@redhat.com>,
	Borislav Petkov <bp@alien8.de>, "H. Peter Anvin" <hpa@zytor.com>,
	Andy Lutomirski <luto@amacapital.net>,
	Kees Cook <keescook@chromium.org>,
	x86@kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/2] x86/math-emu: Add support for FCMOVcc and F[U]COMI[P] insns
Date: Wed, 16 Sep 2015 21:51:35 +0200	[thread overview]
Message-ID: <55F9C847.5070104@redhat.com> (raw)
In-Reply-To: <1442432914-27022-1-git-send-email-dvlasenk@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 411 bytes --]

On 09/16/2015 09:48 PM, Denys Vlasenko wrote:
> Run-tested by booting with "no387 nofxsr" and running test programs:
> 
> # ./test_FCMOV
> [RUN]	Testing fcmovCC instructions
> [OK]	fcmovCC
> # ./test_FCOMI
> [RUN]	Testing f[u]comi[p] instructions
> [OK]	f[u]comi[p]

The sources for these test programs are in this email.

Ingo, let me know if you want a patch which adds them
to tools/testing/selftests/x86/*


[-- Attachment #2: test_FCMOV.c --]
[-- Type: text/x-csrc, Size: 2101 bytes --]

#undef _GNU_SOURCE
#define _GNU_SOURCE 1
#undef __USE_GNU
#define __USE_GNU 1
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
//#include <sys/ptrace.h>
#include <sys/wait.h>

#define TEST(insn) \
long double __attribute__((noinline)) insn(long flags) \
{						\
	long double out;			\
	asm ("\n"				\
	"	push	%1""\n"			\
	"	popf""\n"			\
	"	fldpi""\n"			\
	"	fld1""\n"			\
 	"	" #insn " %%st(1), %%st" "\n"	\
 	"	ffree	%%st(1)" "\n"		\
	: "=t" (out)				\
	: "r" (flags)				\
	);					\
	return out;				\
}

TEST(fcmovb)
TEST(fcmove)
TEST(fcmovbe)
TEST(fcmovu)
TEST(fcmovnb)
TEST(fcmovne)
TEST(fcmovnbe)
TEST(fcmovnu)

enum {
	CF = 1 << 0,
	PF = 1 << 2,
	ZF = 1 << 6,
};

int main(int argc, char **argv, char **envp)
{
	int err = 0;

	printf("[RUN]\tTesting fcmovCC instructions\n");
	/* If fcmovCC() returns 1.0, the move wasn't done */
	err |= !(fcmovb(0)   == 1.0); err |= !(fcmovnb(0)  != 1.0);
	err |= !(fcmove(0)   == 1.0); err |= !(fcmovne(0)  != 1.0);
	err |= !(fcmovbe(0)  == 1.0); err |= !(fcmovnbe(0) != 1.0);
	err |= !(fcmovu(0)   == 1.0); err |= !(fcmovnu(0)  != 1.0);

	err |= !(fcmovb(CF)  != 1.0); err |= !(fcmovnb(CF)  == 1.0);
	err |= !(fcmove(CF)  == 1.0); err |= !(fcmovne(CF)  != 1.0);
	err |= !(fcmovbe(CF) != 1.0); err |= !(fcmovnbe(CF) == 1.0);
	err |= !(fcmovu(CF)  == 1.0); err |= !(fcmovnu(CF)  != 1.0);

	err |= !(fcmovb(ZF)  == 1.0); err |= !(fcmovnb(ZF)  != 1.0);
	err |= !(fcmove(ZF)  != 1.0); err |= !(fcmovne(ZF)  == 1.0);
	err |= !(fcmovbe(ZF) != 1.0); err |= !(fcmovnbe(ZF) == 1.0);
	err |= !(fcmovu(ZF)  == 1.0); err |= !(fcmovnu(ZF)  != 1.0);

	err |= !(fcmovb(PF)  == 1.0); err |= !(fcmovnb(PF)  != 1.0);
	err |= !(fcmove(PF)  == 1.0); err |= !(fcmovne(PF)  != 1.0);
	err |= !(fcmovbe(PF) == 1.0); err |= !(fcmovnbe(PF) != 1.0);
	err |= !(fcmovu(PF)  != 1.0); err |= !(fcmovnu(PF)  == 1.0);

        if (!err)
                printf("[OK]\tfcmovCC\n");
	else
		printf("[FAIL]\tfcmovCC errors: %d\n", err);

	return err;
}

[-- Attachment #3: test_FCOMI.c --]
[-- Type: text/x-csrc, Size: 7121 bytes --]

#undef _GNU_SOURCE
#define _GNU_SOURCE 1
#undef __USE_GNU
#define __USE_GNU 1
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
//#include <sys/ptrace.h>
#include <sys/wait.h>
#include <fenv.h>

enum {
	CF = 1 << 0,
	PF = 1 << 2,
	ZF = 1 << 6,
	ARITH = CF | PF | ZF,
};

long res_fcomi_pi_1;
long res_fcomi_1_pi;
long res_fcomi_1_1;
long res_fcomi_nan_1;
/* sNaN is s|111 1111 1|1xx xxxx xxxx xxxx xxxx xxxx */
/* qNaN is s|111 1111 1|0xx xxxx xxxx xxxx xxxx xxxx (some x must be nonzero) */
int snan = 0x7fc11111;
int qnan = 0x7f811111;
unsigned short snan1[5];
/* sNaN80 is s|111 1111 1111 1111 |10xx xx...xx (some x must be nonzero) */
unsigned short snan80[5] = { 0x1111, 0x1111, 0x1111, 0x8111, 0x7fff };

int test(long flags)
{
	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);

	asm ("\n"

	"	push	%0""\n"
	"	popf""\n"
	"	fld1""\n"
	"	fldpi""\n"
 	"	fcomi	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
 	"	ffree	%%st(1)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_1_pi""\n"

	"	push	%0""\n"
	"	popf""\n"
	"	fldpi""\n"
	"	fld1""\n"
 	"	fcomi	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
 	"	ffree	%%st(1)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_pi_1""\n"

	"	push	%0""\n"
	"	popf""\n"
	"	fld1""\n"
	"	fld1""\n"
 	"	fcomi	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
 	"	ffree	%%st(1)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_1_1""\n"
	:
	: "r" (flags)
	);
	if ((res_fcomi_1_pi & ARITH) != (0)) {
		printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
		return 1;
	}
	if ((res_fcomi_pi_1 & ARITH) != (CF)) {
		printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
		return 1;
	}
	if ((res_fcomi_1_1 & ARITH) != (ZF)) {
		printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
		return 1;
	}
	if (fetestexcept(FE_INVALID) != 0) {
		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
		return 1;
	}
	return 0;
}

int test_qnan(long flags)
{
	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);

	asm ("\n"
	"	push	%0""\n"
	"	popf""\n"
	"	flds	qnan""\n"
	"	fld1""\n"
	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
 	"	fcomi	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
 	"	ffree	%%st(1)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_nan_1""\n"
	:
	: "r" (flags)
	);
	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
		return 1;
	}
	if (fetestexcept(FE_INVALID) != FE_INVALID) {
		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
		return 1;
	}
	return 0;
}

int testu_qnan(long flags)
{
	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);

	asm ("\n"
	"	push	%0""\n"
	"	popf""\n"
	"	flds	qnan""\n"
	"	fld1""\n"
	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
 	"	fucomi	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
 	"	ffree	%%st(1)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_nan_1""\n"
	:
	: "r" (flags)
	);
	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
		return 1;
	}
	if (fetestexcept(FE_INVALID) != 0) {
		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
		return 1;
	}
	return 0;
}

int testu_snan(long flags)
{
	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);

	asm ("\n"
	"	push	%0""\n"
	"	popf""\n"
//	"	flds	snan""\n"	// WRONG, this will convert 32-bit fp snan to a *qnan* in 80-bit fp register!
//	"	fstpt	snan1""\n"	// if uncommented, it prints "snan1:7fff c111 1100 0000 0000" - c111, not 8111!
//	"	fnclex""\n"		// flds of a snan raised FE_INVALID, clear it
	"	fldt	snan80""\n"	// fldt never raise FE_INVALID
	"	fld1""\n"
 	"	fucomi	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
 	"	ffree	%%st(1)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_nan_1""\n"
	:
	: "r" (flags)
	);
	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
		return 1;
	}
//	printf("snan:%x snan1:%04x %04x %04x %04x %04x\n", snan, snan1[4], snan1[3], snan1[2], snan1[1], snan1[0]);
	if (fetestexcept(FE_INVALID) != FE_INVALID) {
		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
		return 1;
	}
	return 0;
}

int testp(long flags)
{
	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);

	asm ("\n"

	"	push	%0""\n"
	"	popf""\n"
	"	fld1""\n"
	"	fldpi""\n"
 	"	fcomip	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_1_pi""\n"

	"	push	%0""\n"
	"	popf""\n"
	"	fldpi""\n"
	"	fld1""\n"
 	"	fcomip	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_pi_1""\n"

	"	push	%0""\n"
	"	popf""\n"
	"	fld1""\n"
	"	fld1""\n"
 	"	fcomip	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_1_1""\n"
	:
	: "r" (flags)
	);
	if ((res_fcomi_1_pi & ARITH) != (0)) {
		printf("[BAD]\tfcomi_1_pi with flags:%lx\n", flags);
		return 1;
	}
	if ((res_fcomi_pi_1 & ARITH) != (CF)) {
		printf("[BAD]\tfcomi_pi_1 with flags:%lx->%lx\n", flags, res_fcomi_pi_1 & ARITH);
		return 1;
	}
	if ((res_fcomi_1_1 & ARITH) != (ZF)) {
		printf("[BAD]\tfcomi_1_1 with flags:%lx\n", flags);
		return 1;
	}
	if (fetestexcept(FE_INVALID) != 0) {
		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
		return 1;
	}
	return 0;
}

int testp_qnan(long flags)
{
	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);

	asm ("\n"
	"	push	%0""\n"
	"	popf""\n"
	"	flds	qnan""\n"
	"	fld1""\n"
	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
 	"	fcomip	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_nan_1""\n"
	:
	: "r" (flags)
	);
	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
		return 1;
	}
	if (fetestexcept(FE_INVALID) != FE_INVALID) {
		printf("[BAD]\tFE_INVALID is not set in %s\n", __func__);
		return 1;
	}
	return 0;
}

int testup_qnan(long flags)
{
	feclearexcept(FE_DIVBYZERO|FE_INEXACT|FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW);

	asm ("\n"
	"	push	%0""\n"
	"	popf""\n"
	"	flds	qnan""\n"
	"	fld1""\n"
	"	fnclex""\n"		// fld of a qnan raised FE_INVALID, clear it
 	"	fucomip	%%st(1), %%st" "\n"
 	"	ffree	%%st(0)" "\n"
	"	pushf""\n"
	"	pop	res_fcomi_nan_1""\n"
	:
	: "r" (flags)
	);
	if ((res_fcomi_nan_1 & ARITH) != (ZF|CF|PF)) {
		printf("[BAD]\tfcomi_qnan_1 with flags:%lx\n", flags);
		return 1;
	}
	if (fetestexcept(FE_INVALID) != 0) {
		printf("[BAD]\tFE_INVALID is set in %s\n", __func__);
		return 1;
	}
	return 0;
}

int main(int argc, char **argv, char **envp)
{
	int err = 0;

        printf("[RUN]\tTesting f[u]comi[p] instructions\n");
	err |= test(0);
	err |= test_qnan(0);
	err |= testu_qnan(0);
	err |= testu_snan(0);
	err |= test(CF|ZF|PF);
	err |= test_qnan(CF|ZF|PF);
	err |= testu_qnan(CF|ZF|PF);
	err |= testu_snan(CF|ZF|PF);
	err |= testp(0);
	err |= testp_qnan(0);
	err |= testup_qnan(0);
	err |= testp(CF|ZF|PF);
	err |= testp_qnan(CF|ZF|PF);
	err |= testup_qnan(CF|ZF|PF);
	if (!err)
		printf("[OK]\tf[u]comi[p]\n");
	else
		printf("[FAIL]\tf[u]comi[p] errors: %d\n", err);

	return err;
}

  parent reply	other threads:[~2015-09-16 19:51 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-16 19:48 [PATCH 1/2] x86/math-emu: Add support for FCMOVcc and F[U]COMI[P] insns Denys Vlasenko
2015-09-16 19:48 ` [PATCH 2/2] x86/math-emu: Remove define layer for undocumented opcodes Denys Vlasenko
2015-09-18  7:36   ` Ingo Molnar
2015-09-16 19:51 ` Denys Vlasenko [this message]
2015-09-17  7:22   ` [PATCH 1/2] x86/math-emu: Add support for FCMOVcc and F[U]COMI[P] insns Ingo Molnar
2015-09-18  7:33 ` Ingo Molnar
2015-09-18 14:53   ` Denys Vlasenko
2015-09-20  8:13     ` Ingo Molnar

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55F9C847.5070104@redhat.com \
    --to=dvlasenk@redhat.com \
    --cc=bp@alien8.de \
    --cc=hpa@zytor.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@amacapital.net \
    --cc=mingo@kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.