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.

246 lines
7.5 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software and the related documents are Intel copyrighted materials, and your
* use of them is governed by the express license under which they were provided to
* you ("License"). Unless the License provides otherwise, you may not use, modify,
* copy, publish, distribute, disclose or transmit this software or the related
* documents without Intel's prior written permission.
*
* 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.
*/
// <COMPONENT>: util
// <FILE-TYPE>: component public header
#ifndef UTIL_INTEL_FP_HPP
#define UTIL_INTEL_FP_HPP
namespace UTIL {
/*!
* An 80-bit X87 data register padded out to 128-bits.
*/
union /*<POD>*/ X87REG_PADDED
{
struct
{
UINT64 _significand; ///< The floating-point significand.
UINT16 _exponent; ///< The floating-point exponent, top bit is the sign bit.
UINT16 _pad[3];
} _fp;
struct
{
UINT64 _lo; ///< Least significant part of value.
UINT64 _hi; ///< Most significant part of value.
} _raw;
};
/*!
* A 128-bit XMM register value.
*/
union /*<POD>*/ XMMREG
{
UINT8 _vec8[16]; ///< Vector of 16 8-bit elements.
UINT16 _vec16[8]; ///< Vector of 8 16-bit elements.
UINT32 _vec32[4]; ///< Vector of 4 32-bit elements.
UINT64 _vec64[2]; ///< Vector of 2 64-bit elements.
};
/*!
* The memory format written by the FXSAVE instruction for IA32.
*/
struct /*<POD>*/ FXSAVE_IA32
{
UINT16 _fcw; ///< X87 control word.
UINT16 _fsw; ///< X87 status word.
UINT8 _ftw; ///< Abridged X87 tag value.
UINT8 _pad1;
UINT16 _fop; ///< Last X87 non-control instruction opcode.
UINT32 _fpuip; ///< Last X87 non-control instruction address.
UINT16 _cs; ///< Last X87 non-control instruction CS selector.
UINT16 _pad2;
UINT32 _fpudp; ///< Last X87 non-control instruction operand address.
UINT16 _ds; ///< Last X87 non-control instruction operand DS selector.
UINT16 _pad3;
UINT32 _mxcsr; ///< MXCSR control and status register.
UINT32 _mxcsrmask; ///< Mask of valid MXCSR bits.
X87REG_PADDED _sts[8]; ///< X87 data registers in top-of-stack order.
XMMREG _xmms[8]; ///< XMM registers.
UINT8 _pad4[224];
};
/*!
* The memory format written by the FXSAVE instruction for Intel64 (default operand size).
*/
struct /*<POD>*/ FXSAVE_INTEL64_DEFAULT
{
UINT16 _fcw; ///< X87 control word.
UINT16 _fsw; ///< X87 status word.
UINT8 _ftw; ///< Abridged X87 tag value.
UINT8 _pad1;
UINT16 _fop; ///< Last X87 non-control instruction opcode.
UINT32 _fpuip; ///< Last X87 non-control instruction segment offset.
UINT16 _cs; ///< Last X87 non-control instruction CS selector.
UINT16 _pad2;
UINT32 _fpudp; ///< Last X87 non-control instruction operand segment offset.
UINT16 _ds; ///< Last X87 non-control instruction operand DS selector.
UINT16 _pad3;
UINT32 _mxcsr; ///< MXCSR control and status register.
UINT32 _mxcsrmask; ///< Mask of valid MXCSR bits.
X87REG_PADDED _sts[8]; ///< X87 data registers in top-of-stack order.
XMMREG _xmms[16]; ///< XMM registers. (at most 16 registers, on 32 bit system only 8 are accessible).
UINT8 _pad4[96];
};
/*!
* The memory format written by the FXSAVE instruction for Intel64 (promoted operand size).
*/
struct /*<POD>*/ FXSAVE_INTEL64_PROMOTED
{
UINT16 _fcw; ///< X87 control word.
UINT16 _fsw; ///< X87 status word.
UINT8 _ftw; ///< Abridged X87 tag value.
UINT8 _pad1;
UINT16 _fop; ///< Last X87 non-control instruction opcode.
UINT64 _fpuip; ///< Last X87 non-control instruction address.
UINT64 _fpudp; ///< Last X87 non-control operand address.
UINT32 _mxcsr; ///< MXCSR control and status register.
UINT32 _mxcsrmask; ///< Mask of valid MXCSR bits.
X87REG_PADDED _sts[8]; ///< X87 data registers in top-of-stack order.
XMMREG _xmms[16]; ///< XMM registers.
UINT8 _pad4[96];
};
/*!
* Convert an X87 tag register value from the 16-bit full form to its 8-bit
* abridged form (as saved by the FXSAVE instruction).
*
* @param[in] fullTag The tag value in full form.
*
* @return The tag value in abridged form.
*/
inline UINT8 GetX87AbridgedTag(UINT16 fullTag)
{
const UINT16 empty = 3;
UINT8 tags = 0;
UINT16 mask = 3;
for (int i = 0; i < 8; i++)
{
UINT8 tag;
if ((fullTag & mask) == (empty << 2*i))
tag = 0;
else
tag = 1;
tags |= (tag << i);
mask <<= 2;
}
return tags;
}
/*!
* Get the 16-bit "full form" of X87 tag register value from an FXSAVE buffer.
*
* @tparam FXSAVE One of the three FXSAVE buffer types: FXSAVE_IA32,
* FXSAVE_INTEL64_DEFAULT, or FXSAVE_INTEL64_PROMOTED.
* @param[in] fxsave The FXSAVE buffer data.
*/
template<typename FXSAVE> UINT16 GetX87FullTag(const FXSAVE *fxsave)
{
// This algorithm follows the algorithm in the IA-32 Intel Architecture Software Developer's
// Manual, Volume 2A. See the section on the FXSAVE instruction.
UINT16 tags = 0;
UINT8 ftw = fxsave->_ftw;
unsigned tos = (fxsave->_fsw >> 11) & 0x7;
const UINT16 valid = 0;
const UINT16 zero = 1;
const UINT16 special = 2;
const UINT16 empty = 3;
const UINT64 jbit = UINT64(1) << 63;
for (unsigned i = 0; i < 8; i++)
{
UINT16 tag;
if (!(ftw & 1))
{
tag = empty;
}
else
{
// The tag bits are in physical order, but the ST registers are in top-of-stack order. Subtract the TOS
// base to get the corresponding ST register.
//
unsigned streg = (i - tos) & 0x7;
const X87REG_PADDED *reg = &fxsave->_sts[streg];
UINT16 exponent = reg->_fp._exponent & 0x7fff;
if (exponent == 0x7fff)
{
tag = special;
}
else if (exponent == 0)
{
if (!reg->_fp._significand)
{
tag = zero;
}
else
{
tag = special;
}
}
else
{
if (reg->_fp._significand & jbit)
tag = valid;
else
tag = special;
}
}
tags |= (tag << (2*i));
ftw >>= 1;
}
return tags;
}
/*!
* Get a simplified version of the 16-bit "full form" of the X87 tag register
* value from the 8-bit "abridged" version. The simplified version has the
* 16-bit format, but each tag value is either 00B (valid) or 11B (empty).
*
* @param[in] abridgedTag The 8-bit arbidged tag value.
*
* @return The simplified version of the 16-bit tag value.
*/
inline UINT16 GetSimpleX87FullTag(UINT8 abridgedTag)
{
const UINT16 valid = 0;
const UINT16 empty = 3;
UINT16 tags = 0;
for (unsigned i = 0; i < 8; i++)
{
UINT16 tag = (abridgedTag & 1) ? valid : empty;
tags |= (tag << (2*i));
abridgedTag >>= 1;
}
return tags;
}
} // namespace
#endif // file guard