diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py index 0b2e81cbd..b18d48264 100644 --- a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py +++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py @@ -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") diff --git a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py index 16196bcc8..d9a83dfde 100644 --- a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py +++ b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py @@ -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 }; ''' diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa index 35f319528..b751b9b4f 100644 --- a/src/arch/x86/isa/microops/regop.isa +++ b/src/arch/x86/isa/microops/regop.isa @@ -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; } ''' }}; diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index 5d101a5ae..ba8f63a0e 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -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