X86: Change how segment loading is performed.

This commit is contained in:
Gabe Black 2008-06-12 00:52:12 -04:00
parent 129831c116
commit 66f54a6037
4 changed files with 151 additions and 89 deletions

View file

@ -1,4 +1,4 @@
# 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,
@ -85,7 +85,7 @@ def macroop RET_FAR {
ld t1, ss, [1, t0, rsp]
# Get the return CS
ld t2, ss, [1, t0, rsp], dsz
ld t2, ss, [1, t0, rsp], ssz
# Get the rpl
andi t3, t2, 0x3
@ -96,12 +96,21 @@ def macroop RET_FAR {
# that doesn't happen yet.
# Do stuff if they're equal
chks t4, t2, flags=(EZF,)
fault "new GeneralProtection(0)", flags=(CEZF,)
ld t3, flatseg, [1, t0, t4], addressSize=8, dataSize=8
wrdl cs, t3, t2
andi t0, t2, 0xFC, flags=(EZF,), dataSize=2
bri t0, label("processDescriptor"), flags=(CEZF,)
andi t3, t2, 0xF8, dataSize=8
andi t0, t2, 0x4, flags=(EZF,), dataSize=2
bri t0, label("globalDescriptor"), flags=(CEZF,)
ld t3, tsl, [1, t0, t3], dataSize=8
bri t0, label("processDescriptor")
globalDescriptor:
ld t3, tsg, [1, t0, t3], dataSize=8
processDescriptor:
chks t2, t3, IretCheck, dataSize=8
# There should be validity checks on the RIP checks here, but I'll do
# that later.
wrdl reg, t3, t2
wrsel reg, t2
wrip t0, t1
bri t0, label("end")

View file

@ -237,65 +237,104 @@ def macroop MOV_REAL_S_P {
};
def macroop MOV_S_R {
chks t1, regm, flags=(EZF,), dataSize=8
bri t0, label("end"), flags=(CEZF,)
ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
wrdl reg, t2, regm
end:
andi t0, regm, 0xFC, flags=(EZF,), dataSize=2
bri t0, label("processDescriptor"), flags=(CEZF,)
andi t2, regm, 0xF8, dataSize=8
andi t0, regm, 0x4, flags=(EZF,), dataSize=2
bri t0, label("globalDescriptor"), flags=(CEZF,)
ld t3, tsl, [1, t0, t2], dataSize=8
bri t0, label("processDescriptor")
globalDescriptor:
ld t3, tsg, [1, t0, t2], dataSize=8
processDescriptor:
chks regm, t3, dataSize=8
wrdl reg, t3, regm
wrsel reg, regm
};
def macroop MOV_S_M {
ld t1, seg, sib, disp, dataSize=2
chks t2, t1, flags=(EZF,), dataSize=8
bri t0, label("end"), flags=(CEZF,)
ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
wrdl reg, t2, t1
end:
andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
bri t0, label("processDescriptor"), flags=(CEZF,)
andi t2, t1, 0xF8, dataSize=8
andi t0, t1, 0x4, flags=(EZF,), dataSize=2
bri t0, label("globalDescriptor"), flags=(CEZF,)
ld t3, tsl, [1, t0, t2], dataSize=8
bri t0, label("processDescriptor")
globalDescriptor:
ld t3, tsg, [1, t0, t2], dataSize=8
processDescriptor:
chks t1, t3, dataSize=8
wrdl reg, t3, t1
wrsel reg, t1
};
def macroop MOV_S_P {
rdip t7
ld t1, seg, riprel, disp, dataSize=2
chks t2, t1, flags=(EZF,), dataSize=8
bri t0, label("end"), flags=(CEZF,)
ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
wrdl reg, t2, t1
end:
andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
bri t0, label("processDescriptor"), flags=(CEZF,)
andi t2, t1, 0xF8, dataSize=8
andi t0, t1, 0x4, flags=(EZF,), dataSize=2
bri t0, label("globalDescriptor"), flags=(CEZF,)
ld t3, tsl, [1, t0, t2], dataSize=8
bri t0, label("processDescriptor")
globalDescriptor:
ld t3, tsg, [1, t0, t2], dataSize=8
processDescriptor:
chks t1, t3, dataSize=8
wrdl reg, t3, t1
wrsel reg, t1
};
def macroop MOVSS_S_R {
chks t1, regm, flags=(EZF,), dataSize=8
# This actually needs to use the selector as the error code, but it would
# be hard to get that information into the instruction at the moment.
fault "new GeneralProtection(0)", flags=(CEZF,)
ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
wrdl reg, t2, regm
andi t0, regm, 0xFC, flags=(EZF,), dataSize=2
bri t0, label("processDescriptor"), flags=(CEZF,)
andi t2, regm, 0xF8, dataSize=8
andi t0, regm, 0x4, flags=(EZF,), dataSize=2
bri t0, label("globalDescriptor"), flags=(CEZF,)
ld t3, tsl, [1, t0, t2], dataSize=8
bri t0, label("processDescriptor")
globalDescriptor:
ld t3, tsg, [1, t0, t2], dataSize=8
processDescriptor:
chks regm, t3, SSCheck, dataSize=8
wrdl reg, t3, regm
wrsel reg, regm
};
def macroop MOVSS_S_M {
ld t1, seg, sib, disp, dataSize=2
chks t2, t1, flags=(EZF,), dataSize=8
# This actually needs to use the selector as the error code, but it would
# be hard to get that information into the instruction at the moment.
fault "new GeneralProtection(0)", flags=(CEZF,)
ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
wrdl reg, t2, t1
andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
bri t0, label("processDescriptor"), flags=(CEZF,)
andi t2, t1, 0xF8, dataSize=8
andi t0, t1, 0x4, flags=(EZF,), dataSize=2
bri t0, label("globalDescriptor"), flags=(CEZF,)
ld t3, tsl, [1, t0, t2], dataSize=8
bri t0, label("processDescriptor")
globalDescriptor:
ld t3, tsg, [1, t0, t2], dataSize=8
processDescriptor:
chks t1, t3, SSCheck, dataSize=8
wrdl reg, t3, t1
wrsel reg, t1
};
def macroop MOVSS_S_P {
rdip t7
ld t1, seg, riprel, disp, dataSize=2
chks t2, t1, flags=(EZF,), dataSize=8
# This actually needs to use the selector as the error code, but it would
# be hard to get that information into the instruction at the moment.
fault "new GeneralProtection(0)", flags=(CEZF,)
ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
wrdl reg, t2, t1
andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
bri t0, label("processDescriptor"), flags=(CEZF,)
andi t2, t1, 0xF8, dataSize=8
andi t0, t1, 0x4, flags=(EZF,), dataSize=2
bri t0, label("globalDescriptor"), flags=(CEZF,)
ld t3, tsl, [1, t0, t2], dataSize=8
bri t0, label("processDescriptor")
globalDescriptor:
ld t3, tsg, [1, t0, t2], dataSize=8
processDescriptor:
chks t1, t3, SSCheck, dataSize=8
wrdl reg, t3, t1
wrsel reg, t1
};
'''

View file

@ -1030,7 +1030,9 @@ let {{
src1, src2, flags, dataSize)
code = '''
// The selector is in source 1 and can be at most 16 bits.
SegSelector selector = psrc1;
SegSelector selector = DestReg;
SegDescriptor desc = SrcReg1;
HandyM5Reg m5reg = M5Reg;
switch (imm8)
{
@ -1044,15 +1046,31 @@ let {{
"not implemented.\\n");
break;
case SegSSCheck:
panic("SS selector checks not implemented.\\n");
if (selector.si || selector.ti) {
if (!desc.p) {
//FIXME This needs to also push the selector.
return new StackFault;
}
} else {
if ((m5reg.mode != SixtyFourBitMode || m5reg.cpl == 3) ||
!(desc.s == 1 &&
desc.type.codeOrData == 0 && desc.type.w) ||
(desc.dpl != m5reg.cpl) ||
(selector.rpl != m5reg.cpl)) {
return new GeneralProtection(psrc1 & 0xFFFF);
}
}
break;
case SegIretCheck:
{
SegAttr csAttr = CSAttr;
if (!selector.si && !selector.ti)
return new GeneralProtection(psrc1 & 0xFFFF);
if (selector.rpl < csAttr.dpl)
if ((!selector.si && !selector.ti) ||
(selector.rpl < m5reg.cpl) ||
!(desc.s == 1 && desc.type.codeOrData == 1) ||
(!desc.type.c && desc.dpl != selector.rpl) ||
(desc.type.c && desc.dpl > selector.rpl))
return new GeneralProtection(psrc1 & 0xFFFF);
if (!desc.p)
return new SegmentNotPresent;
break;
}
case SegIntCSCheck:
@ -1062,21 +1080,6 @@ let {{
default:
panic("Undefined segment check type.\\n");
}
// Compute the address of the descriptor and set DestReg to it.
if (selector.ti) {
// A descriptor in the LDT
Addr target = (selector.si << 3) + LDTRBase;
if (!LDTRSel || (selector.si << 3) + dataSize > LDTRLimit)
fault = new GeneralProtection(selector & mask(16));
DestReg = target;
} else {
// A descriptor in the GDT
Addr target = (selector.si << 3) + GDTRBase;
if ((selector.si << 3) + dataSize > GDTRLimit)
fault = new GeneralProtection(selector & mask(16));
DestReg = target;
}
'''
flag_code = '''
// Check for a NULL selector and set ZF,EZF appropriately.
@ -1108,32 +1111,39 @@ let {{
class Wrdl(RegOp):
code = '''
SegDescriptor desc = SrcReg1;
SegAttr attr = 0;
attr.dpl = desc.dpl;
attr.defaultSize = desc.d;
if (!desc.s) {
SegSelector selector = SrcReg2;
if (selector.si || selector.ti) {
SegAttr attr = 0;
attr.dpl = desc.dpl;
attr.defaultSize = desc.d;
if (!desc.s) {
SegBaseDest = SegBaseDest;
SegLimitDest = SegLimitDest;
SegAttrDest = SegAttrDest;
panic("System segment encountered.\\n");
} else {
if (!desc.p)
panic("Segment not present.\\n");
if (desc.type.codeOrData) {
attr.readable = desc.type.r;
attr.longMode = desc.l;
} else {
attr.expandDown = desc.type.e;
attr.readable = 1;
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;
SegAttrDest = attr;
}
} else {
SegBaseDest = SegBaseDest;
SegLimitDest = SegLimitDest;
SegAttrDest = SegAttrDest;
panic("System segment encountered.\\n");
} else {
if (!desc.p)
panic("Segment not present.\\n");
if (desc.type.codeOrData) {
attr.readable = desc.type.r;
attr.longMode = desc.l;
} else {
attr.expandDown = desc.type.e;
attr.readable = 1;
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;
SegAttrDest = attr;
}
'''
}};

View file

@ -574,14 +574,18 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
// Check for a NULL segment selector.
if (!tc->readMiscRegNoEffect(MISCREG_SEG_SEL(seg)))
return new GeneralProtection(0);
SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
if (!attr.writable && write)
return new GeneralProtection(0);
if (!attr.readable && !write && !execute)
return new GeneralProtection(0);
bool expandDown = false;
if (seg >= SEGMENT_REG_ES && seg <= SEGMENT_REG_HS) {
SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
if (!attr.writable && write)
return new GeneralProtection(0);
if (!attr.readable && !write && !execute)
return new GeneralProtection(0);
expandDown = attr.expandDown;
}
Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg));
Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg));
if (!attr.expandDown) {
if (expandDown) {
DPRINTF(TLB, "Checking an expand down segment.\n");
// We don't have to worry about the access going around the
// end of memory because accesses will be broken up into