x86: Add helper functions to access rflags
The rflags register is spread across several different registers. Most of the flags are stored in MISCREG_RFLAGS, but some are stored in microcode registers. When accessing RFLAGS, we need to reconstruct it from these registers. This changeset adds two functions, X86ISA::getRFlags() and X86ISA::setRFlags(), that take care of this magic.
This commit is contained in:
@@ -236,5 +236,36 @@ skipFunction(ThreadContext *tc)
|
||||
panic("Not implemented for x86\n");
|
||||
}
|
||||
|
||||
uint64_t
|
||||
getRFlags(ThreadContext *tc)
|
||||
{
|
||||
const uint64_t ncc_flags(tc->readMiscRegNoEffect(MISCREG_RFLAGS));
|
||||
const uint64_t cc_flags(tc->readIntReg(X86ISA::INTREG_PSEUDO(0)));
|
||||
const uint64_t cfof_bits(tc->readIntReg(X86ISA::INTREG_PSEUDO(1)));
|
||||
const uint64_t df_bit(tc->readIntReg(X86ISA::INTREG_PSEUDO(2)));
|
||||
// ecf (PSEUDO(3)) & ezf (PSEUDO(4)) are only visible to
|
||||
// microcode, so we can safely ignore them.
|
||||
|
||||
// Reconstruct the real rflags state, mask out internal flags, and
|
||||
// make sure reserved bits have the expected values.
|
||||
return ((ncc_flags | cc_flags | cfof_bits | df_bit) & 0x3F7FD5)
|
||||
| 0x2;
|
||||
}
|
||||
|
||||
void
|
||||
setRFlags(ThreadContext *tc, uint64_t val)
|
||||
{
|
||||
tc->setIntReg(X86ISA::INTREG_PSEUDO(0), val & ccFlagMask);
|
||||
tc->setIntReg(X86ISA::INTREG_PSEUDO(1), val & cfofMask);
|
||||
tc->setIntReg(X86ISA::INTREG_PSEUDO(2), val & DFBit);
|
||||
|
||||
// Internal microcode registers (ECF & EZF)
|
||||
tc->setIntReg(X86ISA::INTREG_PSEUDO(3), 0);
|
||||
tc->setIntReg(X86ISA::INTREG_PSEUDO(4), 0);
|
||||
|
||||
// Update the RFLAGS misc reg with whatever didn't go into the
|
||||
// magic registers.
|
||||
tc->setMiscReg(MISCREG_RFLAGS, val & ~(ccFlagMask | cfofMask | DFBit));
|
||||
}
|
||||
|
||||
} // namespace X86_ISA
|
||||
|
||||
@@ -105,6 +105,35 @@ namespace X86ISA
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reconstruct the rflags register from the internal gem5 register
|
||||
* state.
|
||||
*
|
||||
* gem5 stores rflags in several different registers to avoid
|
||||
* pipeline dependencies. In order to get the true rflags value,
|
||||
* we can't simply read the value of MISCREG_RFLAGS. Instead, we
|
||||
* need to read out various state from microcode registers and
|
||||
* merge that with MISCREG_RFLAGS.
|
||||
*
|
||||
* @param tc Thread context to read rflags from.
|
||||
* @return rflags as seen by the guest.
|
||||
*/
|
||||
uint64_t getRFlags(ThreadContext *tc);
|
||||
|
||||
/**
|
||||
* Set update the rflags register and internal gem5 state.
|
||||
*
|
||||
* @note This function does not update MISCREG_M5_REG. You might
|
||||
* need to update this register by writing anything to
|
||||
* MISCREG_M5_REG with side-effects.
|
||||
*
|
||||
* @see X86ISA::getRFlags()
|
||||
*
|
||||
* @param tc Thread context to update
|
||||
* @param val New rflags value to store in TC
|
||||
*/
|
||||
void setRFlags(ThreadContext *tc, uint64_t val);
|
||||
}
|
||||
|
||||
#endif // __ARCH_X86_UTILITY_HH__
|
||||
|
||||
Reference in New Issue
Block a user