Index: trunk/src/VBox/VMM/TRPM.cpp
===================================================================
--- trunk/src/VBox/VMM/TRPM.cpp	(revision 5395)
+++ trunk/src/VBox/VMM/TRPM.cpp	(revision 5396)
@@ -518,7 +518,6 @@
     STAM_REG(pVM, &pVM->trpm.s.StatForwardProfHC,       STAMTYPE_PROFILE_ADV, "/TRPM/ForwardRaw/Prof/HC",         STAMUNIT_TICKS_PER_CALL, "Profiling TRPMForwardTrap.");
 
-    STAM_REG(pVM, &pVM->trpm.s.StatTrap0dDisasm,        STAMTYPE_PROFILE_ADV, "/TRPM/Trap0d/Prof/Disasm",         STAMUNIT_TICKS_PER_CALL, "Profiling trpmGCTrap0dHandler.");
-    STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRing0RdTsc,    STAMTYPE_COUNTER, "/TRPM/Trap0d/RdTsc-R0",                    STAMUNIT_OCCURENCES, "Number of RDTSC #GPs from guest ring-0.");
-    STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRing3RdTsc,    STAMTYPE_COUNTER, "/TRPM/Trap0d/RdTsc-R3",                    STAMUNIT_OCCURENCES, "Number of RDTSC #GPs from guest ring-3.");
+    STAM_REG(pVM, &pVM->trpm.s.StatTrap0dDisasm,        STAMTYPE_PROFILE, "/TRPM/GC/Traps/0d/Disasm",              STAMUNIT_TICKS_PER_CALL, "Profiling disassembly part of trpmGCTrap0dHandler.");
+    STAM_REG(pVM, &pVM->trpm.s.StatTrap0dRdTsc,         STAMTYPE_COUNTER, "/TRPM/GC/Traps/0d/RdTsc",                   STAMUNIT_OCCURENCES, "Number of RDTSC #GPs.");
 
     /*
Index: trunk/src/VBox/VMM/TRPMInternal.h
===================================================================
--- trunk/src/VBox/VMM/TRPMInternal.h	(revision 5395)
+++ trunk/src/VBox/VMM/TRPMInternal.h	(revision 5396)
@@ -174,7 +174,6 @@
     STAMPROFILEADV  StatForwardProfGC;
     STAMPROFILEADV  StatForwardProfHC;
-    STAMPROFILEADV  StatTrap0dDisasm;
-    STAMCOUNTER     StatTrap0dRing0RdTsc;   /**< Number of RDTSC #GPs from guest ring-0. */
-    STAMCOUNTER     StatTrap0dRing3RdTsc;   /**< Number of RDTSC #GPs from guest ring-3. */
+    STAMPROFILE     StatTrap0dDisasm;
+    STAMCOUNTER     StatTrap0dRdTsc;        /**< Number of RDTSC #GPs. */
 
     /* R3: Statistics for interrupt handlers (allocated on the hypervisor heap). */
Index: trunk/src/VBox/VMM/TRPMInternal.mac
===================================================================
--- trunk/src/VBox/VMM/TRPMInternal.mac	(revision 5395)
+++ trunk/src/VBox/VMM/TRPMInternal.mac	(revision 5396)
@@ -63,7 +63,6 @@
     .StatForwardProfGC        resb STAMPROFILEADV_size
     .StatForwardProfHC        resb STAMPROFILEADV_size
-    .StatTrap0dDisasm         resb STAMPROFILEADV_size
-    .StatTrap0dRing0RdTsc     resb STAMCOUNTER_size
-    .StatTrap0dRing3RdTsc     resb STAMCOUNTER_size
+    .StatTrap0dDisasm         resb STAMPROFILE_size
+    .StatTrap0dRdTsc          resb STAMCOUNTER_size
 
     .paStatForwardedIRQR3  RTR3PTR_RES 1
Index: trunk/src/VBox/VMM/VMMAll/SELMAll.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMAll/SELMAll.cpp	(revision 5395)
+++ trunk/src/VBox/VMM/VMMAll/SELMAll.cpp	(revision 5396)
@@ -321,7 +321,31 @@
 
 /**
- * Validates and converts a GC selector based code address to a flat address.
- *
- * @returns Flat address.
+ * Validates and converts a GC selector based code address to a flat
+ * address when in real or v8086 mode.
+ *
+ * @returns VINF_SUCCESS.
+ * @param   pVM     VM Handle.
+ * @param   SelCS   Selector part.
+ * @param   pHidCS  The hidden CS register part. Optional.
+ * @param   Addr    Address part.
+ * @param   ppvFlat Where to store the flat address.
+ */
+DECLINLINE(int) selmValidateAndConvertCSAddrRealMode(PVM pVM, RTSEL SelCS, PCPUMSELREGHID pHidCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
+{
+    RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
+    if (!pHidCS || !CPUMAreHiddenSelRegsValid(pVM))
+        uFlat += ((RTGCUINTPTR)SelCS << 4);
+    else
+        uFlat += pHidCS->u32Base;
+    *ppvFlat = (RTGCPTR)uFlat;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Validates and converts a GC selector based code address to a flat
+ * address when in protected/long mode using the standard algorithm.
+ *
+ * @returns VBox status code.
  * @param   pVM     VM Handle.
  * @param   SelCPL  Current privilege level. Get this from SS - CS might be conforming!
@@ -330,6 +354,7 @@
  * @param   Addr    Address part.
  * @param   ppvFlat Where to store the flat address.
- */
-static int selmValidateAndConvertCSAddr(PVM pVM, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
+ * @param   pcBits  Where to store the segment bitness (16/32/64). Optional.
+ */
+DECLINLINE(int) selmValidateAndConvertCSAddrStd(PVM pVM, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat, uint32_t *pcBits)
 {
     Assert(!CPUMAreHiddenSelRegsValid(pVM));
@@ -378,10 +403,11 @@
                 if ((RTGCUINTPTR)Addr <= u32Limit)
                 {
-                    if (ppvFlat)
-                        *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr
-                                               + (   (Desc.Gen.u8BaseHigh2 << 24)
-                                                  |  (Desc.Gen.u8BaseHigh1 << 16)
-                                                  |   Desc.Gen.u16BaseLow)
-                                                 );
+                    *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr
+                                           + (   (Desc.Gen.u8BaseHigh2 << 24)
+                                              |  (Desc.Gen.u8BaseHigh1 << 16)
+                                              |   Desc.Gen.u16BaseLow)
+                                             );
+                    if (pcBits)
+                        *pcBits = Desc.Gen.u1DefBig ? 32 : 16; /** @todo GUEST64 */
                     return VINF_SUCCESS;
                 }
@@ -397,7 +423,93 @@
 
 /**
+ * Validates and converts a GC selector based code address to a flat
+ * address when in protected/long mode using the standard algorithm.
+ *
+ * @returns VBox status code.
+ * @param   pVM     VM Handle.
+ * @param   SelCPL  Current privilege level. Get this from SS - CS might be conforming!
+ *                  A full selector can be passed, we'll only use the RPL part.
+ * @param   SelCS   Selector part.
+ * @param   Addr    Address part.
+ * @param   ppvFlat Where to store the flat address.
+ * @param   pcBits  Where to store the segment bitness (16/32/64). Optional.
+ */
+DECLINLINE(int) selmValidateAndConvertCSAddrHidden(PVM pVM, RTSEL SelCPL, RTSEL SelCS, PCPUMSELREGHID pHidCS, RTGCPTR Addr, PRTGCPTR ppvFlat)
+{
+    /*
+     * Check if present.
+     */
+    if (pHidCS->Attr.n.u1Present)
+    {
+        /*
+         * Type check.
+         */
+        if (     pHidCS->Attr.n.u1DescType == 1
+            &&  (pHidCS->Attr.n.u4Type & X86_SEL_TYPE_CODE))
+        {
+            /*
+             * Check level.
+             */
+            unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
+            if (    !(pHidCS->Attr.n.u4Type & X86_SEL_TYPE_CONF)
+                ?   uLevel <= pHidCS->Attr.n.u2Dpl
+                :   uLevel >= pHidCS->Attr.n.u2Dpl /* hope I got this right now... */
+                    )
+            {
+                /*
+                 * Limit check.
+                 */
+                uint32_t    u32Limit = pHidCS->u32Limit;
+                /** @todo correct with hidden limit value?? */
+                if (pHidCS->Attr.n.u1Granularity)
+                    u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
+                if ((RTGCUINTPTR)Addr <= u32Limit)
+                {
+                    *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr + pHidCS->u32Base );
+                    return VINF_SUCCESS;
+                }
+                return VERR_OUT_OF_SELECTOR_BOUNDS;
+            }
+            return VERR_INVALID_RPL;
+        }
+        return VERR_NOT_CODE_SELECTOR;
+    }
+    return VERR_SELECTOR_NOT_PRESENT;
+}
+
+
+/**
  * Validates and converts a GC selector based code address to a flat address.
  *
- * @returns Flat address.
+ * This is like SELMValidateAndConvertCSAddr + SELMIsSelector32Bit but with
+ * invalid hidden CS data. It's customized for dealing efficiently with CS
+ * at GC trap time.
+ *
+ * @returns VBox status code.
+ * @param   pVM          VM Handle.
+ * @param   eflags       Current eflags
+ * @param   SelCPL       Current privilege level. Get this from SS - CS might be conforming!
+ *                       A full selector can be passed, we'll only use the RPL part.
+ * @param   SelCS        Selector part.
+ * @param   Addr         Address part.
+ * @param   ppvFlat      Where to store the flat address.
+ * @param   pcBits       Where to store the 64-bit/32-bit/16-bit indicator.
+ */
+SELMDECL(int) SELMValidateAndConvertCSAddrGCTrap(PVM pVM, X86EFLAGS eflags, RTSEL SelCPL, RTSEL SelCS, RTGCPTR Addr, PRTGCPTR ppvFlat, uint32_t *pcBits)
+{
+    if (    CPUMIsGuestInRealMode(pVM)
+        ||  eflags.Bits.u1VM)
+    {
+        *pcBits = 16;
+        return selmValidateAndConvertCSAddrRealMode(pVM, SelCS, NULL, Addr, ppvFlat);
+    }
+    return selmValidateAndConvertCSAddrStd(pVM, SelCPL, SelCS, Addr, ppvFlat, pcBits);
+}
+
+
+/**
+ * Validates and converts a GC selector based code address to a flat address.
+ *
+ * @returns VBox status code.
  * @param   pVM          VM Handle.
  * @param   eflags       Current eflags
@@ -411,70 +523,12 @@
 SELMDECL(int) SELMValidateAndConvertCSAddr(PVM pVM, X86EFLAGS eflags, RTSEL SelCPL, RTSEL SelCS, CPUMSELREGHID *pHiddenCSSel, RTGCPTR Addr, PRTGCPTR ppvFlat)
 {
-    /*
-     * Deal with real & v86 mode first.
-     */
     if (    CPUMIsGuestInRealMode(pVM)
         ||  eflags.Bits.u1VM)
-    {
-        if (ppvFlat)
-        {
-            RTGCUINTPTR uFlat = (RTGCUINTPTR)Addr & 0xffff;
-
-            if (!CPUMAreHiddenSelRegsValid(pVM))
-                uFlat += ((RTGCUINTPTR)SelCS << 4);
-            else
-                uFlat += pHiddenCSSel->u32Base;
-
-            *ppvFlat = (RTGCPTR)uFlat;
-        }
-        return VINF_SUCCESS;
-    }
-
-    /** @todo when we're in 16 bits mode, we should cut off the address as well.. */
-
+        return selmValidateAndConvertCSAddrRealMode(pVM, SelCS, pHiddenCSSel, Addr, ppvFlat);
+
+    /** @todo when we're in 16 bits mode, we should cut off the address as well? (like in selmValidateAndConvertCSAddrRealMode) */
     if (!CPUMAreHiddenSelRegsValid(pVM))
-        return selmValidateAndConvertCSAddr(pVM, SelCPL, SelCS, Addr, ppvFlat);
-
-    /*
-     * Check if present.
-     */
-    if (pHiddenCSSel->Attr.n.u1Present)
-    {
-        /*
-         * Type check.
-         */
-        if (     pHiddenCSSel->Attr.n.u1DescType == 1
-            &&  (pHiddenCSSel->Attr.n.u4Type & X86_SEL_TYPE_CODE))
-        {
-            /*
-             * Check level.
-             */
-            unsigned uLevel = RT_MAX(SelCPL & X86_SEL_RPL, SelCS & X86_SEL_RPL);
-            if (    !(pHiddenCSSel->Attr.n.u4Type & X86_SEL_TYPE_CONF)
-                ?   uLevel <= pHiddenCSSel->Attr.n.u2Dpl
-                :   uLevel >= pHiddenCSSel->Attr.n.u2Dpl /* hope I got this right now... */
-                    )
-            {
-                /*
-                 * Limit check.
-                 */
-                uint32_t    u32Limit = pHiddenCSSel->u32Limit;
-                /** @todo correct with hidden limit value?? */
-                if (pHiddenCSSel->Attr.n.u1Granularity)
-                    u32Limit = (u32Limit << PAGE_SHIFT) | PAGE_OFFSET_MASK;
-                if ((RTGCUINTPTR)Addr <= u32Limit)
-                {
-                    if (ppvFlat)
-                        *ppvFlat = (RTGCPTR)(  (RTGCUINTPTR)Addr + pHiddenCSSel->u32Base );
-
-                    return VINF_SUCCESS;
-                }
-                return VERR_OUT_OF_SELECTOR_BOUNDS;
-            }
-            return VERR_INVALID_RPL;
-        }
-        return VERR_NOT_CODE_SELECTOR;
-    }
-    return VERR_SELECTOR_NOT_PRESENT;
+        return selmValidateAndConvertCSAddrStd(pVM, SelCPL, SelCS, Addr, ppvFlat, NULL);
+    return selmValidateAndConvertCSAddrHidden(pVM, SelCPL, SelCS, pHiddenCSSel, Addr, ppvFlat);
 }
 
Index: trunk/src/VBox/VMM/VMMGC/TRPMGCHandlers.cpp
===================================================================
--- trunk/src/VBox/VMM/VMMGC/TRPMGCHandlers.cpp	(revision 5395)
+++ trunk/src/VBox/VMM/VMMGC/TRPMGCHandlers.cpp	(revision 5396)
@@ -525,18 +525,4 @@
     switch (pCpu->pCurInstr->opcode)
     {
-        /*
-         * Since we're usually trapping RDTSC there may be a high volume
-         * of these instructions. So, put it first and go straight to
-         * the emulation function to save time.
-         */
-        case OP_RDTSC:
-            STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRing0RdTsc);
-            rc = EMInterpretRdtsc(pVM, pRegFrame);
-            if (RT_SUCCESS(rc))
-                pRegFrame->eip += pCpu->opsize;
-            else if (rc == VERR_EM_INTERPRETER)
-                rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
-            return trpmGCExitTrap(pVM, rc, pRegFrame);
-
         case OP_INT3:
             /*
@@ -599,4 +585,5 @@
         case OP_LLDT:
         case OP_STI:
+        case OP_RDTSC:  /* just in case */
         case OP_CLTS:
         {
@@ -675,15 +662,16 @@
 
         /*
-         * Handle virtualized TSC reads.
-         * Call the emulation function directly to skip unnecessary overhead.
+         * Handle virtualized TSC reads, just in case.
          */
         case OP_RDTSC:
-            STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRing3RdTsc);
-            rc = EMInterpretRdtsc(pVM, pRegFrame);
-            if (RT_SUCCESS(rc))
+        {
+            uint32_t cbIgnored;
+            rc = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, PC, &cbIgnored);
+            if (VBOX_SUCCESS(rc))
                 pRegFrame->eip += pCpu->opsize;
             else if (rc == VERR_EM_INTERPRETER)
                 rc = VINF_EM_RAW_EXCEPTION_PRIVILEGED;
             return trpmGCExitTrap(pVM, rc, pRegFrame);
+        }
 
         /*
@@ -712,4 +700,28 @@
 
 /**
+ * Emulates RDTSC for the \#GP handler.
+ *
+ * @returns VINF_SUCCESS or VINF_EM_RAW_EMULATE_INSTR.
+ *
+ * @param   pVM         Pointer to the shared VM structure.
+ * @param   pRegFrame   Pointer to the registre frame for the trap.
+ *                      This will be updated on successful return.
+ */
+DECLINLINE(int) trpmGCTrap0dHandlerRDTSC(PVM pVM, PCPUMCTXCORE pRegFrame)
+{
+    STAM_COUNTER_INC(&pVM->trpm.s.StatTrap0dRdTsc);
+
+    if (CPUMGetGuestCR4(pVM) & X86_CR4_TSD)
+        return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame); /* will trap (optimize later). */
+
+    uint64_t uTicks = TMCpuTickGet(pVM);
+    pRegFrame->eax = uTicks;
+    pRegFrame->edx = uTicks >> 32;
+    pRegFrame->eip += 2;
+    return trpmGCExitTrap(pVM, VINF_SUCCESS, pRegFrame);
+}
+
+
+/**
  * \#GP (General Protection Fault) handler.
  *
@@ -726,41 +738,47 @@
     LogFlow(("trpmGCTrap0dHandler: cs:eip=%RTsel:%VGv uErr=%RX32\n", pRegFrame->ss, pRegFrame->eip, pTrpm->uActiveErrorCode));
 
-#if 0 /* not right for iret. Shouldn't really be needed as SELMValidateAndConvertCSAddr deals with invalid cs. */
-    /*
-     * Filter out selector problems first as these may mean that the
-     * instruction isn't safe to read. If we're here because CS is NIL
-     * the flattening of cs:eip will deal with that.
-     */
-    if (    !(pTrpm->uActiveErrorCode & (X86_TRAP_ERR_IDT | X86_TRAP_ERR_EXTERNAL))
-        &&  (pTrpm->uActiveErrorCode & X86_TRAP_ERR_SEL_MASK))
-    {
-        /* It's a guest trap. */
-        return trpmGCExitTrap(pVM, VINF_EM_RAW_GUEST_TRAP, pRegFrame);
-    }
-#endif
-
-    STAM_PROFILE_ADV_START(&pVM->trpm.s.StatTrap0dDisasm, a);
-    /*
-     * Decode the instruction.
-     */
+    /*
+     * Convert and validate CS.
+     */
+    STAM_PROFILE_START(&pVM->trpm.s.StatTrap0dDisasm, a);
     RTGCPTR PC;
-    int rc = SELMValidateAndConvertCSAddr(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs, &pRegFrame->csHid, (RTGCPTR)pRegFrame->eip, &PC);
-    if (VBOX_FAILURE(rc))
-    {
-        Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Vrc !!\n",
+    uint32_t cBits;
+    int rc = SELMValidateAndConvertCSAddrGCTrap(pVM, pRegFrame->eflags, pRegFrame->ss, pRegFrame->cs,
+                                                (RTGCPTR)pRegFrame->eip, &PC, &cBits);
+    if (RT_FAILURE(rc))
+    {
+        Log(("trpmGCTrap0dHandler: Failed to convert %RTsel:%RX32 (cpl=%d) - rc=%Rrc !!\n",
              pRegFrame->cs, pRegFrame->eip, pRegFrame->ss & X86_SEL_RPL, rc));
-        STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
+        STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
         return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
     }
 
+    /*
+     * Optimize RDTSC traps.
+     * Some guests (like Solaris) is using RDTSC all over the place and
+     * will end up trapping a *lot* because of that.
+     */
+    if (   !pRegFrame->eflags.Bits.u1VM
+        && ((uint8_t *)PC)[0] == 0x0f
+        && ((uint8_t *)PC)[1] == 0x31)
+    {
+        STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
+        return trpmGCTrap0dHandlerRDTSC(pVM, pRegFrame);
+    }
+
+    /*
+     * Disassemble the instruction.
+     */
     DISCPUSTATE Cpu;
     uint32_t    cbOp;
-    rc = EMInterpretDisasOneEx(pVM, (RTGCUINTPTR)PC, pRegFrame, &Cpu, &cbOp);
-    if (VBOX_FAILURE(rc))
-    {
-        STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
+    rc = DISCoreOneEx((RTGCUINTPTR)PC, cBits == 32 ? CPUMODE_32BIT : cBits == 16 ? CPUMODE_16BIT : CPUMODE_64BIT,
+                      NULL, NULL, &Cpu, &cbOp);
+    if (RT_FAILURE(rc))
+    {
+        AssertMsgFailed(("DISCoreOneEx failed to PC=%VGv rc=%Vrc\n", PC, rc));
+        STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
         return trpmGCExitTrap(pVM, VINF_EM_RAW_EMULATE_INSTR, pRegFrame);
     }
-    STAM_PROFILE_ADV_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
+    STAM_PROFILE_STOP(&pVM->trpm.s.StatTrap0dDisasm, a);
 
     /*
@@ -773,5 +791,4 @@
         return trpmGCExitTrap(pVM, rc, pRegFrame);
     }
-
 
     /*
@@ -790,13 +807,12 @@
     /*
      * Deal with v86 code.
-     */
-
-    /* We always set IOPL to zero which makes e.g. pushf fault in V86 mode. The guest might use IOPL=3 and therefor not expect a #GP.
-     * Simply fall back to the recompiler to emulate this instruction.
-     */
-    /* Retrieve the eflags including the virtualized bits. */
-    /** @note hackish as the cpumctxcore structure doesn't contain the right value */
+     *
+     * We always set IOPL to zero which makes e.g. pushf fault in V86
+     * mode. The guest might use IOPL=3 and therefore not expect a #GP.
+     * Simply fall back to the recompiler to emulate this instruction if
+     * that's the case. To get the correct we must use CPUMRawGetEFlags.
+     */
     X86EFLAGS eflags;
-    eflags.u32 = CPUMRawGetEFlags(pVM, pRegFrame);
+    eflags.u32 = CPUMRawGetEFlags(pVM, pRegFrame); /* Get the correct value. */
     if (eflags.Bits.u2IOPL != 3)
     {
