From bfc62d1a7035dfdbad405c0ddbd897ea1174360d Mon Sep 17 00:00:00 2001
From: Gabe Black <gblack@eecs.umich.edu>
Date: Sat, 1 Dec 2007 23:00:15 -0800
Subject: [PATCH] X86: Separate the effective seg base and the "hidden" seg
 base.

--HG--
extra : convert_revision : 5fcb8d94dbab7a7d6fe797277a5856903c885ad4
---
 src/arch/x86/isa/operands.isa  |  4 ++--
 src/arch/x86/linux/syscalls.cc |  2 ++
 src/arch/x86/miscregfile.cc    | 19 +++++++++++++++++++
 src/arch/x86/miscregs.hh       | 20 +++++++++++++++++++-
 src/arch/x86/process.cc        |  1 +
 src/arch/x86/utility.cc        |  6 +++++-
 6 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/src/arch/x86/isa/operands.isa b/src/arch/x86/isa/operands.isa
index f50e71727..7a2631a9c 100644
--- a/src/arch/x86/isa/operands.isa
+++ b/src/arch/x86/isa/operands.isa
@@ -121,11 +121,11 @@ def operands {{
         # The TOP register should needs to be more protected so that later
         # instructions don't map their indexes with an old value.
         'TOP':           ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 61),
-        'SegBase':       ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(segment)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 70),
+        'SegBase':       ('ControlReg', 'uqw', 'MISCREG_SEG_EFF_BASE(segment)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 70),
         'ControlDest':   ('ControlReg', 'uqw', 'MISCREG_CR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 71),
         'ControlSrc1':   ('ControlReg', 'uqw', 'MISCREG_CR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 72),
         'EferOp':        ('ControlReg', 'uqw', 'MISCREG_EFER', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 73),
         'CR4Op':         ('ControlReg', 'uqw', 'MISCREG_CR4', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 74),
-        'CSBase':        ('ControlReg', 'udw', 'MISCREG_CS_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 80),
+        'CSBase':        ('ControlReg', 'udw', 'MISCREG_CS_EFF_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 80),
         'Mem':           ('Mem', 'uqw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 100)
 }};
diff --git a/src/arch/x86/linux/syscalls.cc b/src/arch/x86/linux/syscalls.cc
index c6b2fbb66..ae2ac243b 100644
--- a/src/arch/x86/linux/syscalls.cc
+++ b/src/arch/x86/linux/syscalls.cc
@@ -103,6 +103,7 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
       //Each of these valid options should actually check addr.
       case SetFS:
         tc->setMiscRegNoEffect(MISCREG_FS_BASE, addr);
+        tc->setMiscRegNoEffect(MISCREG_FS_EFF_BASE, addr);
         return 0;
       case GetFS:
         fsBase = tc->readMiscRegNoEffect(MISCREG_FS_BASE);
@@ -110,6 +111,7 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
         return 0;
       case SetGS:
         tc->setMiscRegNoEffect(MISCREG_GS_BASE, addr);
+        tc->setMiscRegNoEffect(MISCREG_GS_EFF_BASE, addr);
         return 0;
       case GetGS:
         gsBase = tc->readMiscRegNoEffect(MISCREG_GS_BASE);
diff --git a/src/arch/x86/miscregfile.cc b/src/arch/x86/miscregfile.cc
index 71908098e..a01902478 100644
--- a/src/arch/x86/miscregfile.cc
+++ b/src/arch/x86/miscregfile.cc
@@ -186,6 +186,25 @@ void MiscRegFile::setReg(int miscReg,
         break;
       case MISCREG_CR8:
         break;
+      case MISCREG_CS_ATTR:
+        {
+            SegAttr toggled = regVal[miscReg] ^ val;
+            SegAttr newCSAttr = val;
+            if (toggled.longMode) {
+                SegAttr newCSAttr = val;
+                if (newCSAttr.longMode) {
+                    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 {
+                    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];
+                }
+            }
+        }
     }
     setRegNoEffect(miscReg, newVal);
 }
diff --git a/src/arch/x86/miscregs.hh b/src/arch/x86/miscregs.hh
index 3a30b9800..d3960073a 100644
--- a/src/arch/x86/miscregs.hh
+++ b/src/arch/x86/miscregs.hh
@@ -270,8 +270,20 @@ namespace X86ISA
         MISCREG_GS_BASE,
         MISCREG_INT_BASE,
 
+        // The effective segment base, ie what is actually added to an
+        // address. In 64 bit mode this can be different from the above,
+        // namely 0.
+        MISCREG_SEG_EFF_BASE_BASE = MISCREG_SEG_BASE_BASE + NumSegments,
+        MISCREG_ES_EFF_BASE = MISCREG_SEG_EFF_BASE_BASE,
+        MISCREG_CS_EFF_BASE,
+        MISCREG_SS_EFF_BASE,
+        MISCREG_DS_EFF_BASE,
+        MISCREG_FS_EFF_BASE,
+        MISCREG_GS_EFF_BASE,
+        MISCREG_INT_EFF_BASE,
+
         // Hidden segment limit field
-        MISCREG_SEG_LIMIT_BASE = MISCREG_SEG_BASE_BASE + NumSegments,
+        MISCREG_SEG_LIMIT_BASE = MISCREG_SEG_EFF_BASE_BASE + NumSegments,
         MISCREG_ES_LIMIT = MISCREG_SEG_LIMIT_BASE,
         MISCREG_CS_LIMIT,
         MISCREG_SS_LIMIT,
@@ -406,6 +418,12 @@ namespace X86ISA
         return (MiscRegIndex)(MISCREG_SEG_BASE_BASE + index);
     }
 
+    static inline MiscRegIndex
+    MISCREG_SEG_EFF_BASE(int index)
+    {
+        return (MiscRegIndex)(MISCREG_SEG_EFF_BASE_BASE + index);
+    }
+
     static inline MiscRegIndex
     MISCREG_SEG_LIMIT(int index)
     {
diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc
index 633b2f136..76f0b5d04 100644
--- a/src/arch/x86/process.cc
+++ b/src/arch/x86/process.cc
@@ -160,6 +160,7 @@ X86LiveProcess::startup()
         //Initialize the segment registers.
         for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
             tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
+            tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
             tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr);
         }
 
diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc
index 0153f10e0..69179c1f4 100644
--- a/src/arch/x86/utility.cc
+++ b/src/arch/x86/utility.cc
@@ -118,6 +118,7 @@ void initCPU(ThreadContext *tc, int cpuId)
     for (int seg = 0; seg != NUM_SEGMENTREGS; seg++) {
         tc->setMiscReg(MISCREG_SEG_SEL(seg), 0);
         tc->setMiscReg(MISCREG_SEG_BASE(seg), 0);
+        tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), 0);
         tc->setMiscReg(MISCREG_SEG_LIMIT(seg), 0xffff);
         tc->setMiscReg(MISCREG_SEG_ATTR(seg), dataAttr);
     }
@@ -130,7 +131,10 @@ void initCPU(ThreadContext *tc, int cpuId)
     codeAttr.defaultSize = 0;
 
     tc->setMiscReg(MISCREG_CS, 0xf000);
-    tc->setMiscReg(MISCREG_CS_BASE, 0x00000000ffff0000ULL);
+    tc->setMiscReg(MISCREG_CS_BASE,
+            0x00000000ffff0000ULL);
+    tc->setMiscReg(MISCREG_CS_EFF_BASE,
+            0x00000000ffff0000ULL);
     // This has the base value pre-added.
     tc->setMiscReg(MISCREG_CS_LIMIT, 0xffffffff);
     tc->setMiscReg(MISCREG_CS_ATTR, codeAttr);
-- 
2.30.2