x86: Add bitfields which can gather/scatter bases and limits.

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>
This commit is contained in:
Gabe Black
2018-01-29 17:49:07 -08:00
parent 497ebfe985
commit 8b66b56b12
4 changed files with 63 additions and 33 deletions

View 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;

View 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;

View 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)

View 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;