X86: Compute PCI config addresses correctly.
[gem5.git] / src / arch / x86 / miscregfile.cc
index 9d8e94061196030b8bd548927d3219041cbce12c..388a83e8df9c89b044c211ade5983435cfce0f04 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * Copyright (c) 2003-2006, 2008 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,7 @@
  */
 
 /*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
  * All rights reserved.
  *
  * Redistribution and use of this software in source and binary forms,
@@ -86,6 +86,9 @@
  */
 
 #include "arch/x86/miscregfile.hh"
+#include "arch/x86/tlb.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
 #include "sim/serialize.hh"
 
 using namespace X86ISA;
@@ -101,62 +104,173 @@ string X86ISA::getMiscRegName(RegIndex index)
 
 void MiscRegFile::clear()
 {
-    //When there are actually misc regs implemented, this will clear them
+    // Blank everything. 0 might not be an appropriate value for some things.
+    memset(regVal, 0, NumMiscRegs * sizeof(MiscReg));
 }
 
-MiscReg MiscRegFile::readRegNoEffect(int miscReg)
+MiscReg MiscRegFile::readRegNoEffect(MiscRegIndex miscReg)
 {
-    switch(miscReg)
-    {
-      case MISCREG_CR1:
-      case MISCREG_CR5:
-      case MISCREG_CR6:
-      case MISCREG_CR7:
-      case MISCREG_CR9:
-      case MISCREG_CR10:
-      case MISCREG_CR11:
-      case MISCREG_CR12:
-      case MISCREG_CR13:
-      case MISCREG_CR14:
-      case MISCREG_CR15:
-        panic("Tried to read invalid control register %d\n", miscReg);
-        break;
-    }
+    // Make sure we're not dealing with an illegal control register.
+    // Instructions should filter out these indexes, and nothing else should
+    // attempt to read them directly.
+    assert( miscReg != MISCREG_CR1 &&
+            !(miscReg > MISCREG_CR4 &&
+              miscReg < MISCREG_CR8) &&
+            !(miscReg > MISCREG_CR8 &&
+              miscReg <= MISCREG_CR15));
+
     return regVal[miscReg];
 }
 
-MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc)
+MiscReg MiscRegFile::readReg(MiscRegIndex miscReg, ThreadContext * tc)
 {
-    warn("No miscreg effects implemented yet!\n");
+    if (miscReg == MISCREG_TSC) {
+        return regVal[MISCREG_TSC] + tc->getCpuPtr()->curCycle();
+    }
     return readRegNoEffect(miscReg);
 }
 
-void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val)
+void MiscRegFile::setRegNoEffect(MiscRegIndex miscReg, const MiscReg &val)
 {
-    switch(miscReg)
-    {
-      case MISCREG_CR1:
-      case MISCREG_CR5:
-      case MISCREG_CR6:
-      case MISCREG_CR7:
-      case MISCREG_CR9:
-      case MISCREG_CR10:
-      case MISCREG_CR11:
-      case MISCREG_CR12:
-      case MISCREG_CR13:
-      case MISCREG_CR14:
-      case MISCREG_CR15:
-        panic("Tried to write invalid control register %d\n", miscReg);
-        break;
-    }
+    // Make sure we're not dealing with an illegal control register.
+    // Instructions should filter out these indexes, and nothing else should
+    // attempt to write to them directly.
+    assert( miscReg != MISCREG_CR1 &&
+            !(miscReg > MISCREG_CR4 &&
+              miscReg < MISCREG_CR8) &&
+            !(miscReg > MISCREG_CR8 &&
+              miscReg <= MISCREG_CR15));
     regVal[miscReg] = val;
 }
 
-void MiscRegFile::setReg(int miscReg,
+void MiscRegFile::setReg(MiscRegIndex miscReg,
         const MiscReg &val, ThreadContext * tc)
 {
-    warn("No miscreg effects implemented yet!\n");
-    setRegNoEffect(miscReg, val);
+    MiscReg newVal = val;
+    switch(miscReg)
+    {
+      case MISCREG_CR0:
+        {
+            CR0 toggled = regVal[miscReg] ^ val;
+            CR0 newCR0 = val;
+            Efer efer = regVal[MISCREG_EFER];
+            HandyM5Reg m5reg = regVal[MISCREG_M5_REG];
+            if (toggled.pg && efer.lme) {
+                if (newCR0.pg) {
+                    //Turning on long mode
+                    efer.lma = 1;
+                    m5reg.mode = LongMode;
+                    regVal[MISCREG_EFER] = efer;
+                } else {
+                    //Turning off long mode
+                    efer.lma = 0;
+                    m5reg.mode = LegacyMode;
+                    regVal[MISCREG_EFER] = efer;
+                }
+            }
+            // Figure out what submode we're in.
+            if (m5reg.mode == LongMode) {
+                SegAttr csAttr = regVal[MISCREG_CS_ATTR];
+                if (csAttr.longMode)
+                    m5reg.submode = SixtyFourBitMode;
+                else
+                    m5reg.submode = CompatabilityMode;
+            } else {
+                if (newCR0.pe) {
+                    RFLAGS rflags = regVal[MISCREG_RFLAGS];
+                    if (rflags.vm)
+                        m5reg.submode = Virtual8086Mode;
+                    else
+                        m5reg.submode = ProtectedMode;
+                } else {
+                    m5reg.submode = RealMode;
+                }
+            }
+            regVal[MISCREG_M5_REG] = m5reg;
+            if (toggled.pg) {
+                tc->getITBPtr()->invalidateAll();
+                tc->getDTBPtr()->invalidateAll();
+            }
+            //This must always be 1.
+            newCR0.et = 1;
+            newVal = newCR0;
+        }
+        break;
+      case MISCREG_CR2:
+        break;
+      case MISCREG_CR3:
+        tc->getITBPtr()->invalidateNonGlobal();
+        tc->getDTBPtr()->invalidateNonGlobal();
+        break;
+      case MISCREG_CR4:
+        {
+            CR4 toggled = regVal[miscReg] ^ val;
+            if (toggled.pae || toggled.pse || toggled.pge) {
+                tc->getITBPtr()->invalidateAll();
+                tc->getDTBPtr()->invalidateAll();
+            }
+        }
+        break;
+      case MISCREG_CR8:
+        break;
+      case MISCREG_CS_ATTR:
+        {
+            SegAttr toggled = regVal[miscReg] ^ val;
+            SegAttr newCSAttr = val;
+            HandyM5Reg m5reg = regVal[MISCREG_M5_REG];
+            if (toggled.longMode) {
+                if (newCSAttr.longMode) {
+                    if (m5reg.mode == LongMode)
+                        m5reg.submode = SixtyFourBitMode;
+                    regVal[MISCREG_ES_EFF_BASE] = 0;
+                    regVal[MISCREG_CS_EFF_BASE] = 0;
+                    regVal[MISCREG_SS_EFF_BASE] = 0;
+                    regVal[MISCREG_DS_EFF_BASE] = 0;
+                } else {
+                    if (m5reg.mode == LongMode)
+                        m5reg.submode = CompatabilityMode;
+                    regVal[MISCREG_ES_EFF_BASE] = regVal[MISCREG_ES_BASE];
+                    regVal[MISCREG_CS_EFF_BASE] = regVal[MISCREG_CS_BASE];
+                    regVal[MISCREG_SS_EFF_BASE] = regVal[MISCREG_SS_BASE];
+                    regVal[MISCREG_DS_EFF_BASE] = regVal[MISCREG_DS_BASE];
+                }
+            }
+            m5reg.cpl = newCSAttr.dpl;
+            regVal[MISCREG_M5_REG] = m5reg;
+        }
+        break;
+      // These segments always actually use their bases, or in other words
+      // their effective bases must stay equal to their actual bases.
+      case MISCREG_FS_BASE:
+      case MISCREG_GS_BASE:
+      case MISCREG_HS_BASE:
+      case MISCREG_TSL_BASE:
+      case MISCREG_TSG_BASE:
+      case MISCREG_TR_BASE:
+      case MISCREG_IDTR_BASE:
+        regVal[MISCREG_SEG_EFF_BASE(miscReg - MISCREG_SEG_BASE_BASE)] = val;
+        break;
+      // These segments ignore their bases in 64 bit mode.
+      // their effective bases must stay equal to their actual bases.
+      case MISCREG_ES_BASE:
+      case MISCREG_CS_BASE:
+      case MISCREG_SS_BASE:
+      case MISCREG_DS_BASE:
+        {
+            Efer efer = regVal[MISCREG_EFER];
+            SegAttr csAttr = regVal[MISCREG_CS_ATTR];
+            if (!efer.lma || !csAttr.longMode) // Check for non 64 bit mode.
+                regVal[MISCREG_SEG_EFF_BASE(miscReg -
+                        MISCREG_SEG_BASE_BASE)] = val;
+        }
+        break;
+      case MISCREG_TSC:
+        regVal[MISCREG_TSC] = val - tc->getCpuPtr()->curCycle();
+        return;
+      default:
+        break;
+    }
+    setRegNoEffect(miscReg, newVal);
 }
 
 void MiscRegFile::serialize(std::ostream & os)