summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas@sandberg.pp.se>2013-06-18 16:10:22 +0200
committerAndreas Sandberg <andreas@sandberg.pp.se>2013-06-18 16:10:22 +0200
commit46a8cbbb7f55e92943cc26266edd98c774edadac (patch)
treeb43adf8ac01539ffbae37748f298e638ee6fe1b8 /src
parentde89e133d8a3f92d9f2f99d0d8bcca50e9da6cb4 (diff)
downloadgem5-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.cc31
-rw-r--r--src/arch/x86/utility.hh29
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__