Index: /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 37057)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAll.cpp	(revision 37058)
@@ -538,10 +538,12 @@
 *******************************************************************************/
 static VBOXSTRICTRC     iemRaiseTaskSwitchFaultCurrentTSS(PIEMCPU pIemCpu);
+static VBOXSTRICTRC     iemRaiseSelectorNotPresent(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess);
+static VBOXSTRICTRC     iemRaiseSelectorNotPresentBySelector(PIEMCPU pIemCpu, uint16_t uSel);
 static VBOXSTRICTRC     iemRaiseSelectorNotPresentWithErr(PIEMCPU pIemCpu, uint16_t uErr);
 static VBOXSTRICTRC     iemRaiseGeneralProtectionFault(PIEMCPU pIemCpu, uint16_t uErr);
 static VBOXSTRICTRC     iemRaiseGeneralProtectionFault0(PIEMCPU pIemCpu);
+static VBOXSTRICTRC     iemRaiseGeneralProtectionFaultBySelector(PIEMCPU pIemCpu, RTSEL uSel);
 static VBOXSTRICTRC     iemRaiseSelectorBounds(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess);
 static VBOXSTRICTRC     iemRaiseSelectorInvalidAccess(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess);
-static VBOXSTRICTRC     iemRaiseSelectorNotPresent(PIEMCPU pIemCpu, uint32_t iSegReg, uint32_t fAccess);
 static VBOXSTRICTRC     iemRaisePageFault(PIEMCPU pIemCpu, RTGCPTR GCPtrWhere, uint32_t fAccess, int rc);
 static VBOXSTRICTRC     iemMemFetchDataU32(PIEMCPU pIemCpu, uint32_t *pu32Dst, uint8_t iSegReg, RTGCPTR GCPtrMem);
@@ -1199,4 +1201,83 @@
     } while (0)
 
+
+/** @name  Misc Worker Functions.
+ * @{
+ */
+
+
+/**
+ * Validates a new SS segment.
+ *
+ * @returns VBox strict status code.
+ * @param   pIemCpu         The IEM per CPU instance data.
+ * @param   pCtx            The CPU context.
+ * @param   NewSS           The new SS selctor.
+ * @param   uCpl            The CPL to load the stack for.
+ * @param   pDesc           Where to return the descriptor.
+ */
+static VBOXSTRICTRC iemMiscValidateNewSS(PIEMCPU pIemCpu, PCCPUMCTX pCtx, RTSEL NewSS, uint8_t uCpl, PIEMSELDESC pDesc)
+{
+    /* Null selectors are not allowed (we're not called for dispatching
+       interrupts with SS=0 in long mode). */
+    if (!(NewSS & (X86_SEL_MASK | X86_SEL_LDT)))
+    {
+        Log(("iemMiscValidateNewSSandRsp: #x - null selector -> #GP(0)\n", NewSS));
+        return iemRaiseGeneralProtectionFault0(pIemCpu);
+    }
+
+    /*
+     * Read the descriptor.
+     */
+    VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pIemCpu, pDesc, NewSS);
+    if (rcStrict != VINF_SUCCESS)
+        return rcStrict;
+
+    /*
+     * Perform the descriptor validation documented for LSS, POP SS and MOV SS.
+     */
+    if (!pDesc->Legacy.Gen.u1DescType)
+    {
+        Log(("iemMiscValidateNewSSandRsp: %#x - system selector -> #GP\n", NewSS, pDesc->Legacy.Gen.u4Type));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
+    }
+
+    if (   (pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
+        || !(pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
+    {
+        Log(("iemMiscValidateNewSSandRsp: %#x - code or read only (%#x) -> #GP\n", NewSS, pDesc->Legacy.Gen.u4Type));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
+    }
+    if (    (pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
+        || !(pDesc->Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
+    {
+        Log(("iemMiscValidateNewSSandRsp: %#x - code or read only (%#x) -> #GP\n", NewSS, pDesc->Legacy.Gen.u4Type));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
+    }
+    /** @todo testcase: check if the TSS.ssX RPL is checked. */
+    if ((NewSS & X86_SEL_RPL) != uCpl)
+    {
+        Log(("iemMiscValidateNewSSandRsp: %#x - RPL and CPL (%d) differs -> #GP\n", NewSS, uCpl));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
+    }
+    if (pDesc->Legacy.Gen.u2Dpl != uCpl)
+    {
+        Log(("iemMiscValidateNewSSandRsp: %#x - DPL (%d) and CPL (%d) differs -> #GP\n", NewSS, pDesc->Legacy.Gen.u2Dpl, uCpl));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, NewSS);
+    }
+
+    /* Is it there? */
+    /** @todo testcase: Is this checked before the canonical / limit check below? */
+    if (!pDesc->Legacy.Gen.u1Present)
+    {
+        Log(("iemMiscValidateNewSSandRsp: %#x - segment not present -> #NP\n", NewSS));
+        return iemRaiseSelectorNotPresentBySelector(pIemCpu, NewSS);
+    }
+
+    return VINF_SUCCESS;
+}
+
+
+/** @}  */
 
 /** @name  Raising Exceptions.
@@ -1528,18 +1609,74 @@
     /** @todo is the RPL of the interrupt/trap gate descriptor checked? */
 
+    /* Check the new EIP against the new CS limit. */
+    uint32_t const uNewEip =    Idte.Gate.u4Type == X86_SEL_TYPE_SYS_286_INT_GATE
+                             || Idte.Gate.u4Type == X86_SEL_TYPE_SYS_286_TRAP_GATE
+                           ? Idte.Gate.u16OffsetLow
+                           : Idte.Gate.u16OffsetLow | ((uint32_t)Idte.Gate.u16OffsetHigh << 16);
+    uint32_t cbLimit = X86DESC_LIMIT(DescCS.Legacy);
+    if (DescCS.Legacy.Gen.u1Granularity)
+        cbLimit = (cbLimit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
+    if (uNewEip > X86DESC_LIMIT(DescCS.Legacy))
+    {
+        Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x - DPL (%d) > CPL (%d) -> #GP\n",
+             u8Vector, NewCS, DescCS.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
+        return iemRaiseGeneralProtectionFault(pIemCpu, NewCS & (X86_SEL_MASK | X86_SEL_LDT));
+    }
+
+    /* Make sure the selector is present. */
+    if (!DescCS.Legacy.Gen.u1Present)
+    {
+        Log(("RaiseXcptOrIntInProtMode %#x - CS=%#x - segment not present -> #NP\n", u8Vector, NewCS));
+        return iemRaiseSelectorNotPresentBySelector(pIemCpu, NewCS);
+    }
+
     /*
      * If the privilege level changes, we need to get a new stack from the TSS.
+     * This in turns means validating the new SS and ESP...
      */
-    uint8_t const uNewCpl = DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF
-                          ? pIemCpu->uCpl : DescCS.Legacy.Gen.u2Dpl;
+    uint8_t const   uNewCpl = DescCS.Legacy.Gen.u4Type & X86_SEL_TYPE_CONF
+                            ? pIemCpu->uCpl : DescCS.Legacy.Gen.u2Dpl;
+    uint32_t        uNewEsp;
+    RTSEL           NewSS;
+    uint32_t        fNewSSAttr;
+    uint32_t        cbNewSSLimit;
+    uint64_t        uNewSSBase;
+
     if (uNewCpl != pIemCpu->uCpl)
     {
-        uint32_t uNewEsp;
-        RTSEL    uNewSs;
-        rcStrict = iemRaiseLoadStackFromTss32Or16(pIemCpu, pCtx, uNewCpl, &uNewSs, &uNewEsp);
+        rcStrict = iemRaiseLoadStackFromTss32Or16(pIemCpu, pCtx, uNewCpl, &NewSS, &uNewEsp);
         if (rcStrict != VINF_SUCCESS)
             return rcStrict;
-
-    }
+        IEMSELDESC DescSS;
+        rcStrict = iemMiscValidateNewSS(pIemCpu, pCtx, NewSS, uNewCpl, &DescSS);
+        if (rcStrict != VINF_SUCCESS)
+            return rcStrict;
+        fNewSSAttr   = X86DESC_GET_HID_ATTR(DescSS.Legacy);
+        cbNewSSLimit = X86DESC_LIMIT(DescSS.Legacy);
+        if (DescSS.Legacy.Gen.u1Granularity)
+            cbNewSSLimit = (cbNewSSLimit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
+        uNewSSBase   = X86DESC_BASE(DescSS.Legacy);
+    }
+    else
+    {
+        uNewEsp      = pCtx->esp;
+        NewSS        = pCtx->ss;
+        fNewSSAttr   = pCtx->ssHid.Attr.u;
+        cbNewSSLimit = pCtx->ssHid.u32Limit;
+        uNewSSBase   = pCtx->ssHid.u64Base;
+    }
+
+    /*
+     * Check if we have the space for the stack frame.
+     */
+
+
+    /*
+     * Set the CS and maybe SS accessed bits.
+     */
+    /** @todo testcase: excatly when is the accessed bit set, before or after
+     *        pushing the stack frame. (write protect the gdt + stack to find
+     *        out). */
+
 
     return VERR_NOT_IMPLEMENTED;
@@ -1741,4 +1878,11 @@
 {
     return iemRaiseGeneralProtectionFault(pIemCpu, 0);
+}
+
+
+/** \#GP(sel) - 0d.  */
+static VBOXSTRICTRC iemRaiseGeneralProtectionFaultBySelector(PIEMCPU pIemCpu, RTSEL Sel)
+{
+    return iemRaiseGeneralProtectionFault(pIemCpu, Sel & (X86_SEL_MASK | X86_SEL_LDT));
 }
 
@@ -4065,5 +4209,5 @@
                  uSel, pCtx->ldtrHid.u32Limit, pCtx->ldtr));
             /** @todo is this the right exception? */
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
 
@@ -4077,5 +4221,5 @@
             Log(("iemMemFetchSelDesc: GDT selector %#x is out of bounds (%3x)\n", uSel, pCtx->gdtr.cbGdt));
             /** @todo is this the right exception? */
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
         GCPtrBase = pCtx->gdtr.pGdt;
@@ -4098,5 +4242,5 @@
             Log(("iemMemFetchSelDesc: system selector %#x is out of bounds\n", uSel));
             /** @todo is this the right exception? */
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
     }
Index: /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 37057)
+++ /trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp.h	(revision 37058)
@@ -723,5 +723,5 @@
 
     /* Is it there? */
-    if (!Desc.Legacy.Gen.u1Present)
+    if (!Desc.Legacy.Gen.u1Present) /** @todo this is probably checked too early. Testcase! */
     {
         Log(("jmpf %04x:%08x -> segment not present\n", uSel, offSeg));
@@ -738,5 +738,5 @@
         {
             Log(("jmpf %04x:%08x -> not a code selector (u4Type=%#x).\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
 
@@ -747,5 +747,5 @@
         {
             Log(("jmpf %04x:%08x -> both L and D are set.\n", uSel, offSeg));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
 
@@ -757,5 +757,5 @@
                 Log(("jmpf %04x:%08x -> DPL violation (conforming); DPL=%d CPL=%u\n",
                      uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
             }
         }
@@ -765,10 +765,10 @@
             {
                 Log(("jmpf %04x:%08x -> CPL != DPL; DPL=%d CPL=%u\n", uSel, offSeg, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
             }
             if ((uSel & X86_SEL_RPL) > pIemCpu->uCpl)
             {
                 Log(("jmpf %04x:%08x -> RPL > DPL; RPL=%d CPL=%u\n", uSel, offSeg, (uSel & X86_SEL_RPL), pIemCpu->uCpl));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
             }
         }
@@ -787,5 +787,5 @@
             {
                 Log(("jmpf %04x:%08x -> out of bounds (%#x)\n", uSel, offSeg, cbLimit));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
             }
             u64Base = X86DESC_BASE(Desc.Legacy);
@@ -834,5 +834,5 @@
             default:
                 Log(("jmpf %04x:%08x -> wrong sys selector (64-bit): %d\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
 
         }
@@ -859,5 +859,5 @@
         default:
             Log(("jmpf %04x:%08x -> wrong sys selector (32-bit): %d\n", uSel, offSeg, Desc.Legacy.Gen.u4Type));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
     }
 }
@@ -1346,5 +1346,5 @@
     {
         Log(("load sreg %d - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
-        return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
     }
     if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
@@ -1354,5 +1354,5 @@
         {
             Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
         if (    (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
@@ -1360,15 +1360,15 @@
         {
             Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
         if ((uSel & X86_SEL_RPL) != pIemCpu->uCpl)
         {
             Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pIemCpu->uCpl));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
         if (Desc.Legacy.Gen.u2Dpl != pIemCpu->uCpl)
         {
             Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pIemCpu->uCpl));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
     }
@@ -1378,5 +1378,5 @@
         {
             Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
-            return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+            return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
         }
         if (   (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
@@ -1389,5 +1389,5 @@
                 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
                      iSegReg, uSel, (uSel & X86_SEL_RPL), pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
             }
 #else /* this is what makes more sense. */
@@ -1396,5 +1396,5 @@
                 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
                      iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
             }
             if (pIemCpu->uCpl > Desc.Legacy.Gen.u2Dpl)
@@ -1402,5 +1402,5 @@
                 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
                      iSegReg, uSel, pIemCpu->uCpl, Desc.Legacy.Gen.u2Dpl));
-                return iemRaiseGeneralProtectionFault(pIemCpu, uSel & (X86_SEL_MASK | X86_SEL_LDT));
+                return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uSel);
             }
 #endif
@@ -1671,5 +1671,5 @@
     {
         Log(("lldt %04x - LDT selector -> #GP\n", uNewLdt));
-        return iemRaiseGeneralProtectionFault(pIemCpu, uNewLdt & (X86_SEL_MASK | X86_SEL_LDT));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewLdt);
     }
 
@@ -1780,5 +1780,5 @@
     {
         Log(("ltr %04x - LDT selector -> #GP\n", uNewTr));
-        return iemRaiseGeneralProtectionFault(pIemCpu, uNewTr & (X86_SEL_MASK | X86_SEL_LDT));
+        return iemRaiseGeneralProtectionFaultBySelector(pIemCpu, uNewTr);
     }
     if ((uNewTr & X86_SEL_MASK) == 0)
