x86: Add bitfields which can gather/scatter bases and limits.
authorGabe Black <gabeblack@google.com>
Tue, 30 Jan 2018 01:49:07 +0000 (17:49 -0800)
committerGabe Black <gabeblack@google.com>
Thu, 15 Mar 2018 00:54:42 +0000 (00:54 +0000)
Add bitfields which can gather/scatter base and limit fields within
"normal" segment descriptors, and in TSS descriptors which have the
same bitfields in the same positions for those two values.

This centralizes the code which manages those bitfields and makes it
less likely that a local implementation will be buggy.

Change-Id: I9809aa626fc31388595c3d3b225c25a0ec6a1275
Reviewed-on: https://gem5-review.googlesource.com/7661
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>

src/arch/x86/isa/microops/regop.isa
src/arch/x86/process.cc
src/arch/x86/regs/misc.hh
src/arch/x86/system.cc

index 2d5ae048a5781622255b46fc1906f097b668d50a..08a4ddd415b3ab8b86c973f7bd96f81c6ad9db18 100644 (file)
@@ -1627,8 +1627,7 @@ let {{
               case LDT64:
               case AvailableTSS64:
               case BusyTSS64:
-                replaceBits(target, 23, 0, desc.baseLow);
-                replaceBits(target, 31, 24, desc.baseHigh);
+                replaceBits(target, 31, 0, desc.base);
                 break;
               case CallGate64:
               case IntGate64:
@@ -1703,12 +1702,8 @@ let {{
                             attr.writable = desc.type.w;
                         }
                     }
-                    Addr base = desc.baseLow | (desc.baseHigh << 24);
-                    Addr limit = desc.limitLow | (desc.limitHigh << 16);
-                    if (desc.g)
-                        limit = (limit << 12) | mask(12);
-                    SegBaseDest = base;
-                    SegLimitDest = limit;
+                    SegBaseDest = desc.base;
+                    SegLimitDest = desc.limit;
                     SegAttrDest = attr;
                 } else {
                     SegBaseDest = SegBaseDest;
index cfec21f393aee00574a9ccb6ebf668b01db087ee..7c979c016e452d9085bd557b546540ae38c598cc 100644 (file)
@@ -244,12 +244,9 @@ X86_64Process::initState()
         initDesc.p = 1;               // present
         initDesc.l = 1;               // longmode - 64 bit
         initDesc.d = 0;               // operand size
-        initDesc.g = 1;               // granularity
         initDesc.s = 1;               // system segment
-        initDesc.limitHigh = 0xFFFF;
-        initDesc.limitLow = 0xF;
-        initDesc.baseHigh = 0x0;
-        initDesc.baseLow = 0x0;
+        initDesc.limit = 0xFFFFFFFF;
+        initDesc.base = 0;
 
         //64 bit code segment
         SegDescriptor csLowPLDesc = initDesc;
@@ -320,11 +317,8 @@ X86_64Process::initState()
         TSSDescLow.type = 0xB;
         TSSDescLow.dpl = 0; // Privelege level 0
         TSSDescLow.p = 1; // Present
-        TSSDescLow.g = 1; // Page granularity
-        TSSDescLow.limitHigh = 0xF;
-        TSSDescLow.limitLow = 0xFFFF;
-        TSSDescLow.baseLow = bits(TSSVirtAddr, 23, 0);
-        TSSDescLow.baseHigh = bits(TSSVirtAddr, 31, 24);
+        TSSDescLow.limit = 0xFFFFFFFF;
+        TSSDescLow.base = bits(TSSVirtAddr, 31, 0);
 
         TSShigh TSSDescHigh = 0;
         TSSDescHigh.base = bits(TSSVirtAddr, 63, 32);
@@ -342,10 +336,8 @@ X86_64Process::initState()
         SegSelector tssSel = 0;
         tssSel.si = numGDTEntries - 1;
 
-        uint64_t tss_base_addr = (TSSDescHigh.base << 32) |
-                                 (TSSDescLow.baseHigh << 24) |
-                                  TSSDescLow.baseLow;
-        uint64_t tss_limit = TSSDescLow.limitLow | (TSSDescLow.limitHigh << 16);
+        uint64_t tss_base_addr = (TSSDescHigh.base << 32) | TSSDescLow.base;
+        uint64_t tss_limit = TSSDescLow.limit;
 
         SegAttr tss_attr = 0;
 
index 48f7d974dbba42ff62714c83aa48d577cc342add..3f3730e32972391b919372b455d352a45555d556 100644 (file)
@@ -43,6 +43,7 @@
 #include "arch/x86/regs/segment.hh"
 #include "arch/x86/x86_traits.hh"
 #include "base/bitunion.hh"
+#include "base/logging.hh"
 
 //These get defined in some system headers (at least termbits.h). That confuses
 //things here significantly.
@@ -867,9 +868,54 @@ namespace X86ISA
      * Segment Descriptors
      */
 
+    class SegDescriptorBase
+    {
+      public:
+        uint32_t
+        getter(const uint64_t &storage) const
+        {
+            return (bits(storage, 63, 56) << 24) | bits(storage, 39, 16);
+        }
+
+        void
+        setter(uint64_t &storage, uint32_t base)
+        {
+            replaceBits(storage, 63, 56, bits(base, 31, 24));
+            replaceBits(storage, 39, 16, bits(base, 23, 0));
+        }
+    };
+
+    class SegDescriptorLimit
+    {
+      public:
+        uint32_t
+        getter(const uint64_t &storage) const
+        {
+            uint32_t limit = (bits(storage, 51, 48) << 16) |
+                             bits(storage, 15, 0);
+            if (bits(storage, 55))
+                limit = (limit << 12) | mask(12);
+            return limit;
+        }
+
+        void
+        setter(uint64_t &storage, uint32_t limit)
+        {
+            bool g = (bits(limit, 31, 24) != 0);
+            panic_if(g && bits(limit, 11, 0) != mask(12),
+                     "Inlimitid segment limit %#x", limit);
+            if (g)
+                limit = limit >> 12;
+            replaceBits(storage, 51, 48, bits(limit, 23, 16));
+            replaceBits(storage, 15, 0, bits(limit, 15, 0));
+            replaceBits(storage, 55, g ? 1 : 0);
+        }
+    };
+
     BitUnion64(SegDescriptor)
         Bitfield<63, 56> baseHigh;
         Bitfield<39, 16> baseLow;
+        BitfieldType<SegDescriptorBase> base;
         Bitfield<55> g; // Granularity
         Bitfield<54> d; // Default Operand Size
         Bitfield<54> b; // Default Operand Size
@@ -877,6 +923,7 @@ namespace X86ISA
         Bitfield<52> avl; // Available To Software
         Bitfield<51, 48> limitHigh;
         Bitfield<15, 0> limitLow;
+        BitfieldType<SegDescriptorLimit> limit;
         Bitfield<47> p; // Present
         Bitfield<46, 45> dpl; // Descriptor Privilege-Level
         Bitfield<44> s; // System
@@ -904,10 +951,12 @@ namespace X86ISA
     BitUnion64(TSSlow)
         Bitfield<63, 56> baseHigh;
         Bitfield<39, 16> baseLow;
+        BitfieldType<SegDescriptorBase> base;
         Bitfield<55> g; // Granularity
         Bitfield<52> avl; // Available To Software
         Bitfield<51, 48> limitHigh;
         Bitfield<15, 0> limitLow;
+        BitfieldType<SegDescriptorLimit> limit;
         Bitfield<47> p; // Present
         Bitfield<46, 45> dpl; // Descriptor Privilege-Level
         SubBitUnion(type, 43, 40)
index b11111d8db7ae46739c776c7a69c9e429c21014b..0f85fdb389effc030f7bf42c830c41b74169ae5f 100644 (file)
@@ -63,14 +63,10 @@ void
 X86ISA::installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
         SegDescriptor desc, bool longmode)
 {
-    uint64_t base = desc.baseLow + (desc.baseHigh << 24);
     bool honorBase = !longmode || seg == SEGMENT_REG_FS ||
                                   seg == SEGMENT_REG_GS ||
                                   seg == SEGMENT_REG_TSL ||
                                   seg == SYS_SEGMENT_REG_TR;
-    uint64_t limit = desc.limitLow | (desc.limitHigh << 16);
-    if (desc.g)
-        limit = (limit << 12) | mask(12);
 
     SegAttr attr = 0;
 
@@ -101,9 +97,9 @@ X86ISA::installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
         attr.expandDown = 0;
     }
 
-    tc->setMiscReg(MISCREG_SEG_BASE(seg), base);
-    tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? base : 0);
-    tc->setMiscReg(MISCREG_SEG_LIMIT(seg), limit);
+    tc->setMiscReg(MISCREG_SEG_BASE(seg), desc.base);
+    tc->setMiscReg(MISCREG_SEG_EFF_BASE(seg), honorBase ? desc.base : 0);
+    tc->setMiscReg(MISCREG_SEG_LIMIT(seg), desc.limit);
     tc->setMiscReg(MISCREG_SEG_ATTR(seg), (MiscReg)attr);
 }
 
@@ -159,10 +155,8 @@ X86System::initState()
     initDesc.d = 0;               // operand size
     initDesc.g = 1;               // granularity
     initDesc.s = 1;               // system segment
-    initDesc.limitHigh = 0xF;
-    initDesc.limitLow = 0xFFFF;
-    initDesc.baseHigh = 0x0;
-    initDesc.baseLow = 0x0;
+    initDesc.limit = 0xFFFFFFFF;
+    initDesc.base = 0;
 
     // 64 bit code segment
     SegDescriptor csDesc = initDesc;