You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.8 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
/*
* This application checks that changes made to the x87, sse and avx registers by the tool, before any application
* modification was made, are in fact visible.
* Since the application does not change these registers, the appropriate bits in the XSTATE_BV save mask are cleared.
* Pin must set the necessary bits in order for the tool's changes to take effect upon xrstor.
*
* Usage: CheckXStateBV <component>
* where component is one of:
* x87 - test the x87 state component
* SSE - test the sse state component
* AVX - test the avx state component
*/
#include <iostream>
#include <cstring>
#include "xstateBVUtils.h"
using std::cerr;
using std::endl;
#ifdef TARGET_WINDOWS
# define ASMNAME(name)
# define ALIGN64 __declspec(align(64))
#else
# define ASMNAME(name) asm(name)
# define ALIGN64 __attribute__ ((aligned (64)))
#endif
/////////////////////
// EXTERNAL FUNCTIONS
/////////////////////
extern "C" void DoXsave() ASMNAME("DoXsave");
/////////////////////
// GLOBAL VARIABLES
/////////////////////
extern "C"
{
unsigned char ALIGN64 xsaveArea[832] ASMNAME("xsaveArea");
unsigned int flags ASMNAME("flags");
}
/////////////////////
// UTILITY FUNCTIONS
/////////////////////
static bool IsOn(TEST_REG_CLASS regClass)
{
const unsigned char xstateBv = xsaveArea[512];
return (xstateBv & xstateBvMasks[regClass]);
}
static void GetRegValue(unsigned char* buf, TEST_REG_CLASS regClass)
{
unsigned int size = testRegSize[regClass];
if (TEST_REG_CLASS_AVX == regClass)
{
// First get the upper half
regClass = TEST_REG_CLASS_SSE;
size = testRegSize[regClass];
memcpy(buf + size, &xsaveArea[testRegLocation[TEST_REG_CLASS_AVX]], size);
// Now get the lower half (xmm)
}
memcpy(buf, &xsaveArea[testRegLocation[regClass]], testRegSize[regClass]);
}
// This is a placeholder for the tool to change the register values.
extern "C" void ChangeRegisterValue() ASMNAME("ChangeRegisterValue");
void ChangeRegisterValue()
{
// does nothing
}
// This is a placeholder for the tool to start execution after changing the register.
extern "C" void ExecuteAt() ASMNAME("ExecuteAt");
void ExecuteAt()
{
// does nothing
}
/////////////////////
// MAIN FUNCTION
/////////////////////
/*
* Expected arguments:
* [1] - component
*/
int main(int argc, const char* argv[])
{
// Verify one command line argument - component
if (argc != 2)
{
cerr << "ERROR: Expected 1 command line argument, got " << argc-1 << ". Aborting test." << endl;
return 1;
}
// Identify the requested state component.
TEST_REG_CLASS regClass = GetTestReg(argv[1]);
if (TEST_REG_CLASS_INVALID == regClass)
{
cerr << "ERROR: Unknown state component '" << argv[1] << "'. Aborting test." << endl;
return 2;
}
// Perform the test.
unsigned char before[32] = { 0 }; // empty buffer large enough to hold any context register up to AVX.
unsigned char after[32] = { 0 }; // empty buffer large enough to hold any context register up to AVX.
flags = 7;
DoXsave(); // get the register value before the change
if (IsOn(regClass))
{
cerr << "WARNING: The " << componentStrings[regClass] << " state bit was expected to be clear at this point "
<< "in the test but it was set." << endl;
}
GetRegValue(before, regClass);
ChangeRegisterValue(); // allow the tool to change the register value.
ExecuteAt();
bool success = true;
flags = 7;
DoXsave(); // get the register value after the change
if (!IsOn(regClass))
{
cerr << "ERROR: The " << componentStrings[regClass] << " state bit was expected to be set at this point "
<< "in the test but it was clear." << endl;
success = false;
}
GetRegValue(after, regClass);
if (0 == memcmp(before, after, testRegSize[regClass]))
{
cerr << "ERROR: Error while testing the " << componentStrings[regClass] << " state. The values before and after "
<< "the test were the same." << endl;
success = false;
}
if (0 != memcmp(after, toolRegisterValues[regClass], testRegSize[regClass]))
{
cerr << "ERROR: Error while testing the " << componentStrings[regClass] << " state. The value after the tool's change "
<< "did not match the expected value." << endl;
success = false;
}
if (!success) return 3;
return 0;
}