diff options
author | Andreas Sandberg <andreas@sandberg.pp.se> | 2013-06-18 16:10:22 +0200 |
---|---|---|
committer | Andreas Sandberg <andreas@sandberg.pp.se> | 2013-06-18 16:10:22 +0200 |
commit | 46a8cbbb7f55e92943cc26266edd98c774edadac (patch) | |
tree | b43adf8ac01539ffbae37748f298e638ee6fe1b8 /src | |
parent | de89e133d8a3f92d9f2f99d0d8bcca50e9da6cb4 (diff) | |
download | gem5-46a8cbbb7f55e92943cc26266edd98c774edadac.tar.xz |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/arch/x86/utility.cc | 31 | ||||
-rw-r--r-- | src/arch/x86/utility.hh | 29 |
2 files changed, 60 insertions, 0 deletions
diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc index e3d25fcdf..2398ca073 100644 --- a/src/arch/x86/utility.cc +++ b/src/arch/x86/utility.cc @@ -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 diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh index f3b0d3fa1..6fc802f2f 100644 --- a/src/arch/x86/utility.hh +++ b/src/arch/x86/utility.hh @@ -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__ |