VirtualBox

Changeset 72575 in vbox


Ignore:
Timestamp:
Jun 15, 2018 9:25:32 PM (7 years ago)
Author:
vboxsync
Message:

NEM/win: Implemented exit optimizations for MMIO, I/O ports, CPUID and MSR exits. Gives a nice speedup (8-10x), except for return-to-ring-3 scenarios. bugref:9044

Location:
trunk/src/VBox/VMM
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h

    r72569 r72575  
    18421842nemHCWinHandleMessageMemory(PVM pVM, PVMCPU pVCpu, HV_X64_MEMORY_INTERCEPT_MESSAGE const *pMsg, PCPUMCTX pCtx, PGVMCPU pGVCpu)
    18431843{
     1844    uint64_t const uHostTsc = ASMReadTSC();
    18441845    Assert(   pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_READ
    18451846           || pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
     
    18911892                      Info.fHasHandlers ? " handlers" : "", Info.fZeroPage    ? " zero-pg" : "",
    18921893                      State.fDidSomething ? "" : " no-change", g_apszHvInterceptAccessTypes[pMsg->Header.InterceptAccessType]));
     1894                EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_NEM, NEMEXITTYPE_MEMORY_ACCESS),
     1895                                 pMsg->Header.Rip + pMsg->Header.CsSegment.Base, uHostTsc);
    18931896                return VINF_SUCCESS;
    18941897            }
     
    19091912     * Emulate the memory access, either access handler or special memory.
    19101913     */
    1911     EMHistoryAddExit(pVCpu,
    1912                        pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
    1913                      ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_WRITE)
    1914                      : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_READ),
    1915                      pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
     1914    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
     1915                                              pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
     1916                                            ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_WRITE)
     1917                                            : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_READ),
     1918                                            pMsg->Header.Rip + pMsg->Header.CsSegment.Base, uHostTsc);
    19161919    nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
    19171920    VBOXSTRICTRC rcStrict;
     
    19311934    if (pMsg->Header.ExecutionState.Reserved0 || pMsg->Header.ExecutionState.Reserved1)
    19321935        Log(("MemExit/Hdr/State: Reserved0=%#x Reserved1=%#x\n", pMsg->Header.ExecutionState.Reserved0, pMsg->Header.ExecutionState.Reserved1));
    1933     //if (pMsg->InstructionByteCount > 0)
    1934     //    Log4(("InstructionByteCount=%#x %.16Rhxs\n", pMsg->InstructionByteCount, pMsg->InstructionBytes));
    1935 
    1936     if (pMsg->InstructionByteCount > 0)
    1937         rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(pCtx), pMsg->Header.Rip,
    1938                                                 pMsg->InstructionBytes, pMsg->InstructionByteCount);
     1936
     1937    if (!pExitRec)
     1938    {
     1939        //if (pMsg->InstructionByteCount > 0)
     1940        //    Log4(("InstructionByteCount=%#x %.16Rhxs\n", pMsg->InstructionByteCount, pMsg->InstructionBytes));
     1941        if (pMsg->InstructionByteCount > 0)
     1942            rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(pCtx), pMsg->Header.Rip,
     1943                                                    pMsg->InstructionBytes, pMsg->InstructionByteCount);
     1944        else
     1945            rcStrict = IEMExecOne(pVCpu);
     1946        /** @todo do we need to do anything wrt debugging here?   */
     1947    }
    19391948    else
    1940         rcStrict = IEMExecOne(pVCpu);
    1941     /** @todo do we need to do anything wrt debugging here?   */
     1949    {
     1950        /* Frequent access or probing. */
     1951        rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     1952        Log4(("MemExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     1953              pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     1954              VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
     1955    }
    19421956    return rcStrict;
    19431957}
     
    19561970nemR3WinHandleExitMemory(PVM pVM, PVMCPU pVCpu, WHV_RUN_VP_EXIT_CONTEXT const *pExit, PCPUMCTX pCtx)
    19571971{
     1972    uint64_t const uHostTsc = ASMReadTSC();
    19581973    Assert(pExit->MemoryAccess.AccessInfo.AccessType != 3);
    19591974    AssertMsg(pExit->VpContext.InstructionLength < 0x10, ("%#x\n", pExit->VpContext.InstructionLength));
     
    19852000                      Info.fHasHandlers ? " handlers" : "", Info.fZeroPage    ? " zero-pg" : "",
    19862001                      State.fDidSomething ? "" : " no-change", g_apszHvInterceptAccessTypes[pExit->MemoryAccess.AccessInfo.AccessType]));
     2002                EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_NEM, NEMEXITTYPE_MEMORY_ACCESS),
     2003                                 pExit->VpContext.Rip + pExit->VpContext.Cs.Base, uHostTsc);
    19872004                return VINF_SUCCESS;
    19882005            }
     
    20032020     * Emulate the memory access, either access handler or special memory.
    20042021     */
    2005     EMHistoryAddExit(pVCpu,
    2006                        pExit->MemoryAccess.AccessInfo.AccessType == WHvMemoryAccessWrite
    2007                      ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_WRITE)
    2008                      : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_READ),
    2009                      pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    2010 
     2022    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
     2023                                              pExit->MemoryAccess.AccessInfo.AccessType == WHvMemoryAccessWrite
     2024                                            ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_WRITE)
     2025                                            : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MMIO_READ),
     2026                                            pExit->VpContext.Rip + pExit->VpContext.Cs.Base, uHostTsc);
    20112027    nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    20122028    rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM | CPUMCTX_EXTRN_DS | CPUMCTX_EXTRN_ES);
    20132029    AssertRCReturn(rc, rc);
    2014 
    20152030    if (pExit->VpContext.ExecutionState.Reserved0 || pExit->VpContext.ExecutionState.Reserved1)
    20162031        Log(("MemExit/Hdr/State: Reserved0=%#x Reserved1=%#x\n", pExit->VpContext.ExecutionState.Reserved0, pExit->VpContext.ExecutionState.Reserved1));
    2017     //if (pMsg->InstructionByteCount > 0)
    2018     //    Log4(("InstructionByteCount=%#x %.16Rhxs\n", pMsg->InstructionByteCount, pMsg->InstructionBytes));
    20192032
    20202033    VBOXSTRICTRC rcStrict;
    2021     if (pExit->MemoryAccess.InstructionByteCount > 0)
    2022         rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(pCtx), pExit->VpContext.Rip,
    2023                                                 pExit->MemoryAccess.InstructionBytes, pExit->MemoryAccess.InstructionByteCount);
     2034    if (!pExitRec)
     2035    {
     2036        //if (pMsg->InstructionByteCount > 0)
     2037        //    Log4(("InstructionByteCount=%#x %.16Rhxs\n", pMsg->InstructionByteCount, pMsg->InstructionBytes));
     2038        if (pExit->MemoryAccess.InstructionByteCount > 0)
     2039            rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(pCtx), pExit->VpContext.Rip,
     2040                                                    pExit->MemoryAccess.InstructionBytes, pExit->MemoryAccess.InstructionByteCount);
     2041        else
     2042            rcStrict = IEMExecOne(pVCpu);
     2043        /** @todo do we need to do anything wrt debugging here?   */
     2044    }
    20242045    else
    2025         rcStrict = IEMExecOne(pVCpu);
    2026     /** @todo do we need to do anything wrt debugging here?   */
     2046    {
     2047        /* Frequent access or probing. */
     2048        rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     2049        Log4(("MemExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     2050              pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2051              VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
     2052    }
    20272053    return rcStrict;
    20282054}
     
    20572083        pCtx->fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT;
    20582084
     2085    /*
     2086     * Add history first to avoid two paths doing EMHistoryExec calls.
     2087     */
    20592088    VBOXSTRICTRC rcStrict;
    2060     if (!pMsg->AccessInfo.StringOp)
    2061     {
    2062         /*
    2063          * Simple port I/O.
    2064          */
    2065         EMHistoryAddExit(pVCpu,
    2066                            pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
    2067                          ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_WRITE)
    2068                          : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_READ),
    2069                          pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
    2070 
    2071         static uint32_t const s_fAndMask[8] =
    2072         {   UINT32_MAX, UINT32_C(0xff), UINT32_C(0xffff), UINT32_MAX,   UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX   };
    2073         uint32_t const        fAndMask      = s_fAndMask[pMsg->AccessInfo.AccessSize];
    2074 
    2075         nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
    2076         if (pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE)
    2077         {
    2078             rcStrict = IOMIOPortWrite(pVM, pVCpu, pMsg->PortNumber, (uint32_t)pMsg->Rax & fAndMask, pMsg->AccessInfo.AccessSize);
    2079             Log4(("IOExit/%u: %04x:%08RX64/%s: OUT %#x, %#x LB %u rcStrict=%Rrc\n",
    2080                   pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    2081                   pMsg->PortNumber, (uint32_t)pMsg->Rax & fAndMask, pMsg->AccessInfo.AccessSize, VBOXSTRICTRC_VAL(rcStrict) ));
    2082             if (IOM_SUCCESS(rcStrict))
    2083                 nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
     2089    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
     2090                                            !pMsg->AccessInfo.StringOp
     2091                                            ? (  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
     2092                                               ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_WRITE)
     2093                                               : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_READ))
     2094                                            : (  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
     2095                                               ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_WRITE)
     2096                                               : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_READ)),
     2097                                            pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
     2098    if (!pExitRec)
     2099    {
     2100        if (!pMsg->AccessInfo.StringOp)
     2101        {
     2102            /*
     2103             * Simple port I/O.
     2104             */
     2105            static uint32_t const s_fAndMask[8] =
     2106            {   UINT32_MAX, UINT32_C(0xff), UINT32_C(0xffff), UINT32_MAX,   UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX   };
     2107            uint32_t const        fAndMask      = s_fAndMask[pMsg->AccessInfo.AccessSize];
     2108
     2109            nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
     2110            if (pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE)
     2111            {
     2112                rcStrict = IOMIOPortWrite(pVM, pVCpu, pMsg->PortNumber, (uint32_t)pMsg->Rax & fAndMask, pMsg->AccessInfo.AccessSize);
     2113                Log4(("IOExit/%u: %04x:%08RX64/%s: OUT %#x, %#x LB %u rcStrict=%Rrc\n",
     2114                      pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2115                      pMsg->PortNumber, (uint32_t)pMsg->Rax & fAndMask, pMsg->AccessInfo.AccessSize, VBOXSTRICTRC_VAL(rcStrict) ));
     2116                if (IOM_SUCCESS(rcStrict))
     2117                    nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
    20842118# ifdef IN_RING0
    2085             else if (   rcStrict == VINF_IOM_R3_IOPORT_WRITE
    2086                      && !pCtx->rflags.Bits.u1TF
    2087                      /** @todo check for debug breakpoints */ )
    2088                 return EMRZSetPendingIoPortWrite(pVCpu, pMsg->PortNumber, pMsg->Header.InstructionLength,
    2089                                                  pMsg->AccessInfo.AccessSize, (uint32_t)pMsg->Rax & fAndMask);
     2119                else if (   rcStrict == VINF_IOM_R3_IOPORT_WRITE
     2120                         && !pCtx->rflags.Bits.u1TF
     2121                         /** @todo check for debug breakpoints */ )
     2122                    return EMRZSetPendingIoPortWrite(pVCpu, pMsg->PortNumber, pMsg->Header.InstructionLength,
     2123                                                     pMsg->AccessInfo.AccessSize, (uint32_t)pMsg->Rax & fAndMask);
    20902124# endif
    2091             else
    2092             {
    2093                 pCtx->rax = pMsg->Rax;
    2094                 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
    2095             }
    2096         }
    2097         else
    2098         {
    2099             uint32_t uValue = 0;
    2100             rcStrict = IOMIOPortRead(pVM, pVCpu, pMsg->PortNumber, &uValue, pMsg->AccessInfo.AccessSize);
    2101             Log4(("IOExit/%u: %04x:%08RX64/%s: IN %#x LB %u -> %#x, rcStrict=%Rrc\n",
    2102                   pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    2103                   pMsg->PortNumber, pMsg->AccessInfo.AccessSize, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
    2104             if (IOM_SUCCESS(rcStrict))
    2105             {
    2106                 if (pMsg->AccessInfo.AccessSize != 4)
    2107                     pCtx->rax = (pMsg->Rax & ~(uint64_t)fAndMask) | (uValue & fAndMask);
    21082125                else
    2109                     pCtx->rax = uValue;
    2110                 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
    2111                 Log4(("IOExit/%u: RAX %#RX64 -> %#RX64\n", pVCpu->idCpu, pMsg->Rax, pCtx->rax));
    2112                 nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
     2126                {
     2127                    pCtx->rax = pMsg->Rax;
     2128                    pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
     2129                }
    21132130            }
    21142131            else
    21152132            {
    2116                 pCtx->rax = pMsg->Rax;
    2117                 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
     2133                uint32_t uValue = 0;
     2134                rcStrict = IOMIOPortRead(pVM, pVCpu, pMsg->PortNumber, &uValue, pMsg->AccessInfo.AccessSize);
     2135                Log4(("IOExit/%u: %04x:%08RX64/%s: IN %#x LB %u -> %#x, rcStrict=%Rrc\n",
     2136                      pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2137                      pMsg->PortNumber, pMsg->AccessInfo.AccessSize, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     2138                if (IOM_SUCCESS(rcStrict))
     2139                {
     2140                    if (pMsg->AccessInfo.AccessSize != 4)
     2141                        pCtx->rax = (pMsg->Rax & ~(uint64_t)fAndMask) | (uValue & fAndMask);
     2142                    else
     2143                        pCtx->rax = uValue;
     2144                    pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
     2145                    Log4(("IOExit/%u: RAX %#RX64 -> %#RX64\n", pVCpu->idCpu, pMsg->Rax, pCtx->rax));
     2146                    nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
     2147                }
     2148                else
     2149                {
     2150                    pCtx->rax = pMsg->Rax;
     2151                    pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
    21182152# ifdef IN_RING0
    2119                 if (   rcStrict == VINF_IOM_R3_IOPORT_READ
    2120                     && !pCtx->rflags.Bits.u1TF
    2121                     /** @todo check for debug breakpoints */ )
    2122                     return EMRZSetPendingIoPortRead(pVCpu, pMsg->PortNumber, pMsg->Header.InstructionLength,
    2123                                                     pMsg->AccessInfo.AccessSize);
     2153                    if (   rcStrict == VINF_IOM_R3_IOPORT_READ
     2154                        && !pCtx->rflags.Bits.u1TF
     2155                        /** @todo check for debug breakpoints */ )
     2156                        return EMRZSetPendingIoPortRead(pVCpu, pMsg->PortNumber, pMsg->Header.InstructionLength,
     2157                                                        pMsg->AccessInfo.AccessSize);
    21242158# endif
     2159                }
    21252160            }
    21262161        }
    2127     }
     2162        else
     2163        {
     2164            /*
     2165             * String port I/O.
     2166             */
     2167            /** @todo Someone at Microsoft please explain how we can get the address mode
     2168             * from the IoPortAccess.VpContext.  CS.Attributes is only sufficient for
     2169             * getting the default mode, it can always be overridden by a prefix.   This
     2170             * forces us to interpret the instruction from opcodes, which is suboptimal.
     2171             * Both AMD-V and VT-x includes the address size in the exit info, at least on
     2172             * CPUs that are reasonably new.
     2173             *
     2174             * Of course, it's possible this is an undocumented and we just need to do some
     2175             * experiments to figure out how it's communicated.  Alternatively, we can scan
     2176             * the opcode bytes for possible evil prefixes.
     2177             */
     2178            nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
     2179            pCtx->fExtrn &= ~(  CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDI | CPUMCTX_EXTRN_RSI
     2180                              | CPUMCTX_EXTRN_DS  | CPUMCTX_EXTRN_ES);
     2181            NEM_WIN_COPY_BACK_SEG(pCtx->ds, pMsg->DsSegment);
     2182            NEM_WIN_COPY_BACK_SEG(pCtx->es, pMsg->EsSegment);
     2183            pCtx->rax = pMsg->Rax;
     2184            pCtx->rcx = pMsg->Rcx;
     2185            pCtx->rdi = pMsg->Rdi;
     2186            pCtx->rsi = pMsg->Rsi;
     2187# ifdef IN_RING0
     2188            rcStrict = nemR0WinImportStateStrict(pGVCpu->pGVM, pGVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "IOExit");
     2189            if (rcStrict != VINF_SUCCESS)
     2190                return rcStrict;
     2191# else
     2192            int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     2193            AssertRCReturn(rc, rc);
     2194            RT_NOREF(pGVCpu);
     2195# endif
     2196
     2197            Log4(("IOExit/%u: %04x:%08RX64/%s: %s%s %#x LB %u (emulating)\n",
     2198                  pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2199                  pMsg->AccessInfo.RepPrefix ? "REP " : "",
     2200                  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE ? "OUTS" : "INS",
     2201                  pMsg->PortNumber, pMsg->AccessInfo.AccessSize ));
     2202            rcStrict = IEMExecOne(pVCpu);
     2203        }
     2204        if (IOM_SUCCESS(rcStrict))
     2205        {
     2206            /*
     2207             * Do debug checks.
     2208             */
     2209            if (   pMsg->Header.ExecutionState.DebugActive /** @todo Microsoft: Does DebugActive this only reflect DR7? */
     2210                || (pMsg->Header.Rflags & X86_EFL_TF)
     2211                || DBGFBpIsHwIoArmed(pVM) )
     2212            {
     2213                /** @todo Debugging. */
     2214            }
     2215        }
     2216        return rcStrict;
     2217    }
     2218
     2219    /*
     2220     * Frequent exit or something needing probing.
     2221     * Get state and call EMHistoryExec.
     2222     */
     2223    nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
     2224    if (!pMsg->AccessInfo.StringOp)
     2225        pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
    21282226    else
    21292227    {
    2130         /*
    2131          * String port I/O.
    2132          */
    2133         /** @todo Someone at Microsoft please explain how we can get the address mode
    2134          * from the IoPortAccess.VpContext.  CS.Attributes is only sufficient for
    2135          * getting the default mode, it can always be overridden by a prefix.   This
    2136          * forces us to interpret the instruction from opcodes, which is suboptimal.
    2137          * Both AMD-V and VT-x includes the address size in the exit info, at least on
    2138          * CPUs that are reasonably new.
    2139          *
    2140          * Of course, it's possible this is an undocumented and we just need to do some
    2141          * experiments to figure out how it's communicated.  Alternatively, we can scan
    2142          * the opcode bytes for possible evil prefixes.
    2143          */
    2144         EMHistoryAddExit(pVCpu,
    2145                            pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
    2146                          ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_WRITE)
    2147                          : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_READ),
    2148                          pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
    2149 
    2150         nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
    21512228        pCtx->fExtrn &= ~(  CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDI | CPUMCTX_EXTRN_RSI
    21522229                          | CPUMCTX_EXTRN_DS  | CPUMCTX_EXTRN_ES);
    21532230        NEM_WIN_COPY_BACK_SEG(pCtx->ds, pMsg->DsSegment);
    21542231        NEM_WIN_COPY_BACK_SEG(pCtx->es, pMsg->EsSegment);
    2155         pCtx->rax = pMsg->Rax;
    21562232        pCtx->rcx = pMsg->Rcx;
    21572233        pCtx->rdi = pMsg->Rdi;
    21582234        pCtx->rsi = pMsg->Rsi;
     2235    }
     2236    pCtx->rax = pMsg->Rax;
     2237
    21592238# ifdef IN_RING0
    2160         rcStrict = nemR0WinImportStateStrict(pGVCpu->pGVM, pGVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "IOExit");
    2161         if (rcStrict != VINF_SUCCESS)
    2162             return rcStrict;
     2239    rcStrict = nemR0WinImportStateStrict(pGVCpu->pGVM, pGVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "IOExit");
     2240    if (rcStrict != VINF_SUCCESS)
     2241        return rcStrict;
    21632242# else
    2164         int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
    2165         AssertRCReturn(rc, rc);
    2166         RT_NOREF(pGVCpu);
     2243    int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     2244    AssertRCReturn(rc, rc);
     2245    RT_NOREF(pGVCpu);
    21672246# endif
    21682247
    2169         Log4(("IOExit/%u: %04x:%08RX64/%s: %s%s %#x LB %u (emulating)\n",
    2170               pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    2171               pMsg->AccessInfo.RepPrefix ? "REP " : "",
    2172               pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE ? "OUTS" : "INS",
    2173               pMsg->PortNumber, pMsg->AccessInfo.AccessSize ));
    2174         rcStrict = IEMExecOne(pVCpu);
    2175     }
    2176     if (IOM_SUCCESS(rcStrict))
    2177     {
    2178         /*
    2179          * Do debug checks.
    2180          */
    2181         if (   pMsg->Header.ExecutionState.DebugActive /** @todo Microsoft: Does DebugActive this only reflect DR7? */
    2182             || (pMsg->Header.Rflags & X86_EFL_TF)
    2183             || DBGFBpIsHwIoArmed(pVM) )
    2184         {
    2185             /** @todo Debugging. */
    2186         }
    2187     }
     2248    Log4(("IOExit/%u: %04x:%08RX64/%s: %s%s%s %#x LB %u -> EMHistoryExec\n",
     2249          pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2250          pMsg->AccessInfo.RepPrefix ? "REP " : "",
     2251          pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE ? "OUT" : "IN",
     2252          pMsg->AccessInfo.StringOp ? "S" : "",
     2253          pMsg->PortNumber, pMsg->AccessInfo.AccessSize));
     2254    rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     2255    Log4(("IOExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     2256          pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2257          VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    21882258    return rcStrict;
    21892259}
     
    22132283        pCtx->fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT;
    22142284
    2215     VBOXSTRICTRC rcStrict;
     2285    /*
     2286     * Add history first to avoid two paths doing EMHistoryExec calls.
     2287     */
     2288    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
     2289                                            !pExit->IoPortAccess.AccessInfo.StringOp
     2290                                            ? (  pExit->MemoryAccess.AccessInfo.AccessType == WHvMemoryAccessWrite
     2291                                               ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_WRITE)
     2292                                               : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_READ))
     2293                                            : (  pExit->MemoryAccess.AccessInfo.AccessType == WHvMemoryAccessWrite
     2294                                               ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_WRITE)
     2295                                               : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_READ)),
     2296                                            pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
     2297    if (!pExitRec)
     2298    {
     2299        VBOXSTRICTRC rcStrict;
     2300        if (!pExit->IoPortAccess.AccessInfo.StringOp)
     2301        {
     2302            /*
     2303             * Simple port I/O.
     2304             */
     2305            static uint32_t const s_fAndMask[8] =
     2306            {   UINT32_MAX, UINT32_C(0xff), UINT32_C(0xffff), UINT32_MAX,   UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX   };
     2307            uint32_t const        fAndMask      = s_fAndMask[pExit->IoPortAccess.AccessInfo.AccessSize];
     2308            if (pExit->IoPortAccess.AccessInfo.IsWrite)
     2309            {
     2310                rcStrict = IOMIOPortWrite(pVM, pVCpu, pExit->IoPortAccess.PortNumber,
     2311                                          (uint32_t)pExit->IoPortAccess.Rax & fAndMask,
     2312                                          pExit->IoPortAccess.AccessInfo.AccessSize);
     2313                Log4(("IOExit/%u: %04x:%08RX64/%s: OUT %#x, %#x LB %u rcStrict=%Rrc\n",
     2314                      pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2315                      pExit->IoPortAccess.PortNumber, (uint32_t)pExit->IoPortAccess.Rax & fAndMask,
     2316                      pExit->IoPortAccess.AccessInfo.AccessSize, VBOXSTRICTRC_VAL(rcStrict) ));
     2317                if (IOM_SUCCESS(rcStrict))
     2318                {
     2319                    nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
     2320                    nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
     2321                }
     2322            }
     2323            else
     2324            {
     2325                uint32_t uValue = 0;
     2326                rcStrict = IOMIOPortRead(pVM, pVCpu, pExit->IoPortAccess.PortNumber, &uValue,
     2327                                         pExit->IoPortAccess.AccessInfo.AccessSize);
     2328                Log4(("IOExit/%u: %04x:%08RX64/%s: IN %#x LB %u -> %#x, rcStrict=%Rrc\n",
     2329                      pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2330                      pExit->IoPortAccess.PortNumber, pExit->IoPortAccess.AccessInfo.AccessSize, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     2331                if (IOM_SUCCESS(rcStrict))
     2332                {
     2333                    if (pExit->IoPortAccess.AccessInfo.AccessSize != 4)
     2334                        pCtx->rax = (pExit->IoPortAccess.Rax & ~(uint64_t)fAndMask) | (uValue & fAndMask);
     2335                    else
     2336                        pCtx->rax = uValue;
     2337                    pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
     2338                    Log4(("IOExit/%u: RAX %#RX64 -> %#RX64\n", pVCpu->idCpu, pExit->IoPortAccess.Rax, pCtx->rax));
     2339                    nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
     2340                    nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
     2341                }
     2342            }
     2343        }
     2344        else
     2345        {
     2346            /*
     2347             * String port I/O.
     2348             */
     2349            /** @todo Someone at Microsoft please explain how we can get the address mode
     2350             * from the IoPortAccess.VpContext.  CS.Attributes is only sufficient for
     2351             * getting the default mode, it can always be overridden by a prefix.   This
     2352             * forces us to interpret the instruction from opcodes, which is suboptimal.
     2353             * Both AMD-V and VT-x includes the address size in the exit info, at least on
     2354             * CPUs that are reasonably new.
     2355             *
     2356             * Of course, it's possible this is an undocumented and we just need to do some
     2357             * experiments to figure out how it's communicated.  Alternatively, we can scan
     2358             * the opcode bytes for possible evil prefixes.
     2359             */
     2360            nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
     2361            pCtx->fExtrn &= ~(  CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDI | CPUMCTX_EXTRN_RSI
     2362                              | CPUMCTX_EXTRN_DS  | CPUMCTX_EXTRN_ES);
     2363            NEM_WIN_COPY_BACK_SEG(pCtx->ds, pExit->IoPortAccess.Ds);
     2364            NEM_WIN_COPY_BACK_SEG(pCtx->es, pExit->IoPortAccess.Es);
     2365            pCtx->rax = pExit->IoPortAccess.Rax;
     2366            pCtx->rcx = pExit->IoPortAccess.Rcx;
     2367            pCtx->rdi = pExit->IoPortAccess.Rdi;
     2368            pCtx->rsi = pExit->IoPortAccess.Rsi;
     2369            int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     2370            AssertRCReturn(rc, rc);
     2371
     2372            Log4(("IOExit/%u: %04x:%08RX64/%s: %s%s %#x LB %u (emulating)\n",
     2373                  pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2374                  pExit->IoPortAccess.AccessInfo.RepPrefix ? "REP " : "",
     2375                  pExit->IoPortAccess.AccessInfo.IsWrite ? "OUTS" : "INS",
     2376                  pExit->IoPortAccess.PortNumber, pExit->IoPortAccess.AccessInfo.AccessSize ));
     2377            rcStrict = IEMExecOne(pVCpu);
     2378        }
     2379        if (IOM_SUCCESS(rcStrict))
     2380        {
     2381            /*
     2382             * Do debug checks.
     2383             */
     2384            if (   pExit->VpContext.ExecutionState.DebugActive /** @todo Microsoft: Does DebugActive this only reflect DR7? */
     2385                || (pExit->VpContext.Rflags & X86_EFL_TF)
     2386                || DBGFBpIsHwIoArmed(pVM) )
     2387            {
     2388                /** @todo Debugging. */
     2389            }
     2390        }
     2391        return rcStrict;
     2392    }
     2393
     2394    /*
     2395     * Frequent exit or something needing probing.
     2396     * Get state and call EMHistoryExec.
     2397     */
     2398    nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    22162399    if (!pExit->IoPortAccess.AccessInfo.StringOp)
    2217     {
    2218         /*
    2219          * Simple port I/O.
    2220          */
    2221         EMHistoryAddExit(pVCpu,
    2222                            pExit->MemoryAccess.AccessInfo.AccessType == WHvMemoryAccessWrite
    2223                          ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_WRITE)
    2224                          : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_READ),
    2225                          pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    2226 
    2227         static uint32_t const s_fAndMask[8] =
    2228         {   UINT32_MAX, UINT32_C(0xff), UINT32_C(0xffff), UINT32_MAX,   UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX   };
    2229         uint32_t const        fAndMask      = s_fAndMask[pExit->IoPortAccess.AccessInfo.AccessSize];
    2230         if (pExit->IoPortAccess.AccessInfo.IsWrite)
    2231         {
    2232             rcStrict = IOMIOPortWrite(pVM, pVCpu, pExit->IoPortAccess.PortNumber, (uint32_t)pExit->IoPortAccess.Rax & fAndMask,
    2233                                       pExit->IoPortAccess.AccessInfo.AccessSize);
    2234             Log4(("IOExit/%u: %04x:%08RX64/%s: OUT %#x, %#x LB %u rcStrict=%Rrc\n",
    2235                   pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    2236                   pExit->IoPortAccess.PortNumber, (uint32_t)pExit->IoPortAccess.Rax & fAndMask,
    2237                   pExit->IoPortAccess.AccessInfo.AccessSize, VBOXSTRICTRC_VAL(rcStrict) ));
    2238             if (IOM_SUCCESS(rcStrict))
    2239             {
    2240                 nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    2241                 nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
    2242             }
    2243         }
    2244         else
    2245         {
    2246             uint32_t uValue = 0;
    2247             rcStrict = IOMIOPortRead(pVM, pVCpu, pExit->IoPortAccess.PortNumber, &uValue, pExit->IoPortAccess.AccessInfo.AccessSize);
    2248             Log4(("IOExit/%u: %04x:%08RX64/%s: IN %#x LB %u -> %#x, rcStrict=%Rrc\n",
    2249                   pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    2250                   pExit->IoPortAccess.PortNumber, pExit->IoPortAccess.AccessInfo.AccessSize, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
    2251             if (IOM_SUCCESS(rcStrict))
    2252             {
    2253                 if (pExit->IoPortAccess.AccessInfo.AccessSize != 4)
    2254                     pCtx->rax = (pExit->IoPortAccess.Rax & ~(uint64_t)fAndMask) | (uValue & fAndMask);
    2255                 else
    2256                     pCtx->rax = uValue;
    2257                 pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
    2258                 Log4(("IOExit/%u: RAX %#RX64 -> %#RX64\n", pVCpu->idCpu, pExit->IoPortAccess.Rax, pCtx->rax));
    2259                 nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    2260                 nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
    2261             }
    2262         }
    2263     }
     2400        pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
    22642401    else
    22652402    {
    2266         /*
    2267          * String port I/O.
    2268          */
    2269         /** @todo Someone at Microsoft please explain how we can get the address mode
    2270          * from the IoPortAccess.VpContext.  CS.Attributes is only sufficient for
    2271          * getting the default mode, it can always be overridden by a prefix.   This
    2272          * forces us to interpret the instruction from opcodes, which is suboptimal.
    2273          * Both AMD-V and VT-x includes the address size in the exit info, at least on
    2274          * CPUs that are reasonably new.
    2275          *
    2276          * Of course, it's possible this is an undocumented and we just need to do some
    2277          * experiments to figure out how it's communicated.  Alternatively, we can scan
    2278          * the opcode bytes for possible evil prefixes.
    2279          */
    2280         EMHistoryAddExit(pVCpu,
    2281                            pExit->MemoryAccess.AccessInfo.AccessType == WHvMemoryAccessWrite
    2282                          ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_WRITE)
    2283                          : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_IO_PORT_STR_READ),
    2284                          pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    2285 
    2286         nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    22872403        pCtx->fExtrn &= ~(  CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDI | CPUMCTX_EXTRN_RSI
    22882404                          | CPUMCTX_EXTRN_DS  | CPUMCTX_EXTRN_ES);
    22892405        NEM_WIN_COPY_BACK_SEG(pCtx->ds, pExit->IoPortAccess.Ds);
    22902406        NEM_WIN_COPY_BACK_SEG(pCtx->es, pExit->IoPortAccess.Es);
    2291         pCtx->rax = pExit->IoPortAccess.Rax;
    22922407        pCtx->rcx = pExit->IoPortAccess.Rcx;
    22932408        pCtx->rdi = pExit->IoPortAccess.Rdi;
    22942409        pCtx->rsi = pExit->IoPortAccess.Rsi;
    2295         int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
    2296         AssertRCReturn(rc, rc);
    2297 
    2298         Log4(("IOExit/%u: %04x:%08RX64/%s: %s%s %#x LB %u (emulating)\n",
    2299               pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    2300               pExit->IoPortAccess.AccessInfo.RepPrefix ? "REP " : "",
    2301               pExit->IoPortAccess.AccessInfo.IsWrite ? "OUTS" : "INS",
    2302               pExit->IoPortAccess.PortNumber, pExit->IoPortAccess.AccessInfo.AccessSize ));
    2303         rcStrict = IEMExecOne(pVCpu);
    2304     }
    2305     if (IOM_SUCCESS(rcStrict))
    2306     {
    2307         /*
    2308          * Do debug checks.
    2309          */
    2310         if (   pExit->VpContext.ExecutionState.DebugActive /** @todo Microsoft: Does DebugActive this only reflect DR7? */
    2311             || (pExit->VpContext.Rflags & X86_EFL_TF)
    2312             || DBGFBpIsHwIoArmed(pVM) )
    2313         {
    2314             /** @todo Debugging. */
    2315         }
    2316     }
     2410    }
     2411    pCtx->rax = pExit->IoPortAccess.Rax;
     2412    int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     2413    AssertRCReturn(rc, rc);
     2414    Log4(("IOExit/%u: %04x:%08RX64/%s: %s%s%s %#x LB %u -> EMHistoryExec\n",
     2415          pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2416          pExit->IoPortAccess.AccessInfo.RepPrefix ? "REP " : "",
     2417          pExit->IoPortAccess.AccessInfo.IsWrite ? "OUT" : "IN",
     2418          pExit->IoPortAccess.AccessInfo.StringOp ? "S" : "",
     2419          pExit->IoPortAccess.PortNumber, pExit->IoPortAccess.AccessInfo.AccessSize));
     2420    VBOXSTRICTRC rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     2421    Log4(("IOExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     2422          pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2423          VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    23172424    return rcStrict;
    2318 
    23192425}
    23202426#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
     
    24012507#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
    24022508
     2509
    24032510#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
    24042511/**
     
    24062513 *
    24072514 * @returns Strict VBox status code.
     2515 * @param   pVM             The cross context VM structure.
    24082516 * @param   pVCpu           The cross context per CPU structure.
    24092517 * @param   pMsg            The message.
    2410  * @param   pCtx            The register context.
     2518 * @param   pGVCpu          The global (ring-0) per CPU structure (NULL in r3).
    24112519 * @sa      nemR3WinHandleExitCpuId
    24122520 */
    2413 NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleMessageCpuId(PVMCPU pVCpu, HV_X64_CPUID_INTERCEPT_MESSAGE const *pMsg, PCPUMCTX pCtx)
     2521NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleMessageCpuId(PVM pVM, PVMCPU pVCpu, HV_X64_CPUID_INTERCEPT_MESSAGE const *pMsg,
     2522                                                        PGVMCPU pGVCpu)
    24142523{
    24152524    AssertMsg(pMsg->Header.InstructionLength < 0x10, ("%#x\n", pMsg->Header.InstructionLength));
    2416 
    2417     /*
    2418      * Soak up state and execute the instruction.
    2419      *
    2420      * Note! If this grows slightly more complicated, combine into an IEMExecDecodedCpuId
    2421      *       function and make everyone use it.
    2422      */
    2423     EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_CPUID),
    2424                      pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
    2425 
    2426     /** @todo Combine implementations into IEMExecDecodedCpuId as this will
    2427      *        only get weirder with nested VT-x and AMD-V support. */
    2428     nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
    2429 
    2430     /* Copy in the low register values (top is always cleared). */
    2431     pCtx->rax = (uint32_t)pMsg->Rax;
    2432     pCtx->rcx = (uint32_t)pMsg->Rcx;
    2433     pCtx->rdx = (uint32_t)pMsg->Rdx;
    2434     pCtx->rbx = (uint32_t)pMsg->Rbx;
    2435     pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
    2436 
    2437     /* Get the correct values. */
    2438     CPUMGetGuestCpuId(pVCpu, pCtx->eax, pCtx->ecx, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
    2439 
    2440     Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 -> %08RX32 / %08RX32 / %08RX32 / %08RX32 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64)\n",
     2525    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_CPUID),
     2526                                            pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
     2527    if (!pExitRec)
     2528    {
     2529        /*
     2530         * Soak up state and execute the instruction.
     2531         *
     2532         * Note! If this grows slightly more complicated, combine into an IEMExecDecodedCpuId
     2533         *       function and make everyone use it.
     2534         */
     2535        /** @todo Combine implementations into IEMExecDecodedCpuId as this will
     2536         *        only get weirder with nested VT-x and AMD-V support. */
     2537        nemHCWinCopyStateFromX64Header(pVCpu, &pVCpu->cpum.GstCtx, &pMsg->Header);
     2538
     2539        /* Copy in the low register values (top is always cleared). */
     2540        pVCpu->cpum.GstCtx.rax = (uint32_t)pMsg->Rax;
     2541        pVCpu->cpum.GstCtx.rcx = (uint32_t)pMsg->Rcx;
     2542        pVCpu->cpum.GstCtx.rdx = (uint32_t)pMsg->Rdx;
     2543        pVCpu->cpum.GstCtx.rbx = (uint32_t)pMsg->Rbx;
     2544        pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
     2545
     2546        /* Get the correct values. */
     2547        CPUMGetGuestCpuId(pVCpu, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx,
     2548                          &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx, &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
     2549
     2550        Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 -> %08RX32 / %08RX32 / %08RX32 / %08RX32 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64)\n",
     2551              pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2552              pMsg->Rax,                           pMsg->Rcx,              pMsg->Rdx,              pMsg->Rbx,
     2553              pVCpu->cpum.GstCtx.eax,              pVCpu->cpum.GstCtx.ecx, pVCpu->cpum.GstCtx.edx, pVCpu->cpum.GstCtx.ebx,
     2554              pMsg->DefaultResultRax, pMsg->DefaultResultRcx, pMsg->DefaultResultRdx, pMsg->DefaultResultRbx));
     2555
     2556        /* Move RIP and we're done. */
     2557        nemHCWinAdvanceGuestRipAndClearRF(pVCpu, &pVCpu->cpum.GstCtx, &pMsg->Header);
     2558
     2559        return VINF_SUCCESS;
     2560    }
     2561
     2562    /*
     2563     * Frequent exit or something needing probing.
     2564     * Get state and call EMHistoryExec.
     2565     */
     2566    nemHCWinCopyStateFromX64Header(pVCpu, &pVCpu->cpum.GstCtx, &pMsg->Header);
     2567    pVCpu->cpum.GstCtx.rax = pMsg->Rax;
     2568    pVCpu->cpum.GstCtx.rcx = pMsg->Rcx;
     2569    pVCpu->cpum.GstCtx.rdx = pMsg->Rdx;
     2570    pVCpu->cpum.GstCtx.rbx = pMsg->Rbx;
     2571    pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
     2572    Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64) ==> EMHistoryExec\n",
    24412573          pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    24422574          pMsg->Rax,                           pMsg->Rcx,              pMsg->Rdx,              pMsg->Rbx,
    2443           pCtx->eax,                           pCtx->ecx,              pCtx->edx,              pCtx->ebx,
    24442575          pMsg->DefaultResultRax, pMsg->DefaultResultRcx, pMsg->DefaultResultRdx, pMsg->DefaultResultRbx));
    2445 
    2446     /* Move RIP and we're done. */
    2447     nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
    2448 
    2449     return VINF_SUCCESS;
     2576# ifdef IN_RING0
     2577    VBOXSTRICTRC rcStrict = nemR0WinImportStateStrict(pGVCpu->pGVM, pGVCpu, &pVCpu->cpum.GstCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM, "CpuIdExit");
     2578    if (rcStrict != VINF_SUCCESS)
     2579        return rcStrict;
     2580    RT_NOREF(pVM);
     2581# else
     2582    int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, &pVCpu->cpum.GstCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     2583    AssertRCReturn(rc, rc);
     2584    RT_NOREF(pGVCpu);
     2585# endif
     2586    VBOXSTRICTRC rcStrictExec = EMHistoryExec(pVCpu, pExitRec, 0);
     2587    Log4(("CpuIdExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     2588          pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2589          VBOXSTRICTRC_VAL(rcStrictExec), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
     2590    return rcStrictExec;
    24502591}
    24512592#elif defined(IN_RING3)
     
    24572598 * @param   pVCpu           The cross context per CPU structure.
    24582599 * @param   pExit           The VM exit information to handle.
    2459  * @param   pCtx            The register context.
    24602600 * @sa      nemHCWinHandleMessageCpuId
    24612601 */
    24622602NEM_TMPL_STATIC VBOXSTRICTRC
    2463 nemR3WinHandleExitCpuId(PVM pVM, PVMCPU pVCpu, WHV_RUN_VP_EXIT_CONTEXT const *pExit, PCPUMCTX pCtx)
     2603nemR3WinHandleExitCpuId(PVM pVM, PVMCPU pVCpu, WHV_RUN_VP_EXIT_CONTEXT const *pExit)
    24642604{
    24652605    AssertMsg(pExit->VpContext.InstructionLength < 0x10, ("%#x\n", pExit->VpContext.InstructionLength));
    2466 
    2467     /*
    2468      * Soak up state and execute the instruction.
    2469      *
    2470      * Note! If this grows slightly more complicated, combine into an IEMExecDecodedCpuId
    2471      *       function and make everyone use it.
    2472      */
    24732606    PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu, EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_CPUID),
    24742607                                            pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    2475     nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    24762608    if (!pExitRec)
    24772609    {
     2610        /*
     2611         * Soak up state and execute the instruction.
     2612         *
     2613         * Note! If this grows slightly more complicated, combine into an IEMExecDecodedCpuId
     2614         *       function and make everyone use it.
     2615         */
    24782616        /** @todo Combine implementations into IEMExecDecodedCpuId as this will
    24792617         *        only get weirder with nested VT-x and AMD-V support. */
     2618        nemR3WinCopyStateFromX64Header(pVCpu, &pVCpu->cpum.GstCtx, &pExit->VpContext);
    24802619
    24812620        /* Copy in the low register values (top is always cleared). */
    2482         pCtx->rax = (uint32_t)pExit->CpuidAccess.Rax;
    2483         pCtx->rcx = (uint32_t)pExit->CpuidAccess.Rcx;
    2484         pCtx->rdx = (uint32_t)pExit->CpuidAccess.Rdx;
    2485         pCtx->rbx = (uint32_t)pExit->CpuidAccess.Rbx;
    2486         pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
     2621        pVCpu->cpum.GstCtx.rax = (uint32_t)pExit->CpuidAccess.Rax;
     2622        pVCpu->cpum.GstCtx.rcx = (uint32_t)pExit->CpuidAccess.Rcx;
     2623        pVCpu->cpum.GstCtx.rdx = (uint32_t)pExit->CpuidAccess.Rdx;
     2624        pVCpu->cpum.GstCtx.rbx = (uint32_t)pExit->CpuidAccess.Rbx;
     2625        pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
    24872626
    24882627        /* Get the correct values. */
    2489         CPUMGetGuestCpuId(pVCpu, pCtx->eax, pCtx->ecx, &pCtx->eax, &pCtx->ebx, &pCtx->ecx, &pCtx->edx);
     2628        CPUMGetGuestCpuId(pVCpu, pVCpu->cpum.GstCtx.eax, pVCpu->cpum.GstCtx.ecx,
     2629                          &pVCpu->cpum.GstCtx.eax, &pVCpu->cpum.GstCtx.ebx, &pVCpu->cpum.GstCtx.ecx, &pVCpu->cpum.GstCtx.edx);
    24902630
    24912631        Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 -> %08RX32 / %08RX32 / %08RX32 / %08RX32 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64)\n",
    24922632              pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    24932633              pExit->CpuidAccess.Rax,                           pExit->CpuidAccess.Rcx,              pExit->CpuidAccess.Rdx,              pExit->CpuidAccess.Rbx,
    2494               pCtx->eax,                                                     pCtx->ecx,                           pCtx->edx,                           pCtx->ebx,
     2634              pVCpu->cpum.GstCtx.eax,                           pVCpu->cpum.GstCtx.ecx,              pVCpu->cpum.GstCtx.edx,              pVCpu->cpum.GstCtx.ebx,
    24952635              pExit->CpuidAccess.DefaultResultRax, pExit->CpuidAccess.DefaultResultRcx, pExit->CpuidAccess.DefaultResultRdx, pExit->CpuidAccess.DefaultResultRbx));
    24962636
    24972637        /* Move RIP and we're done. */
    2498         nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
     2638        nemR3WinAdvanceGuestRipAndClearRF(pVCpu, &pVCpu->cpum.GstCtx, &pExit->VpContext);
    24992639
    25002640        RT_NOREF_PV(pVM);
     
    25022642    }
    25032643
    2504     /* Get state and call EMHistoryExec. */
    2505     pCtx->rax = pExit->CpuidAccess.Rax;
    2506     pCtx->rcx = pExit->CpuidAccess.Rcx;
    2507     pCtx->rdx = pExit->CpuidAccess.Rdx;
    2508     pCtx->rbx = pExit->CpuidAccess.Rbx;
    2509     pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
     2644    /*
     2645     * Frequent exit or something needing probing.
     2646     * Get state and call EMHistoryExec.
     2647     */
     2648    nemR3WinCopyStateFromX64Header(pVCpu, &pVCpu->cpum.GstCtx, &pExit->VpContext);
     2649    pVCpu->cpum.GstCtx.rax = pExit->CpuidAccess.Rax;
     2650    pVCpu->cpum.GstCtx.rcx = pExit->CpuidAccess.Rcx;
     2651    pVCpu->cpum.GstCtx.rdx = pExit->CpuidAccess.Rdx;
     2652    pVCpu->cpum.GstCtx.rbx = pExit->CpuidAccess.Rbx;
     2653    pVCpu->cpum.GstCtx.fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDX | CPUMCTX_EXTRN_RBX);
    25102654    Log4(("CpuIdExit/%u: %04x:%08RX64/%s: rax=%08RX64 / rcx=%08RX64 / rdx=%08RX64 / rbx=%08RX64 (hv: %08RX64 / %08RX64 / %08RX64 / %08RX64) ==> EMHistoryExec\n",
    25112655          pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    25122656          pExit->CpuidAccess.Rax,                           pExit->CpuidAccess.Rcx,              pExit->CpuidAccess.Rdx,              pExit->CpuidAccess.Rbx,
    25132657          pExit->CpuidAccess.DefaultResultRax, pExit->CpuidAccess.DefaultResultRcx, pExit->CpuidAccess.DefaultResultRdx, pExit->CpuidAccess.DefaultResultRbx));
    2514 
    2515     int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     2658    int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, &pVCpu->cpum.GstCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
    25162659    AssertRCReturn(rc, rc);
    2517 
    25182660    VBOXSTRICTRC rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     2661    Log4(("CpuIdExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     2662          pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2663          VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    25192664    return rcStrict;
    25202665}
    25212666#endif /* IN_RING3 && !NEM_WIN_USE_OUR_OWN_RUN_API */
     2667
    25222668
    25232669#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
     
    25482694    if (pMsg->Header.ExecutionState.Cpl == 0)
    25492695    {
    2550         EMHistoryAddExit(pVCpu,
    2551                            pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
    2552                          ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_WRITE)
    2553                          : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_READ),
    2554                          pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
    2555 
    25562696        /*
    25572697         * Get all the MSR state.  Since we're getting EFER, we also need to
    25582698         * get CR0, CR4 and CR3.
    25592699         */
     2700        PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
     2701                                                  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
     2702                                                ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_WRITE)
     2703                                                : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_READ),
     2704                                                pMsg->Header.Rip + pMsg->Header.CsSegment.Base, ASMReadTSC());
     2705
    25602706        nemHCWinCopyStateFromX64Header(pVCpu, pCtx, &pMsg->Header);
    25612707        rcStrict = nemHCWinImportStateIfNeededStrict(pVCpu, pGVCpu, pCtx,
    2562                                                        CPUMCTX_EXTRN_ALL_MSRS | CPUMCTX_EXTRN_CR0
     2708                                                     (!pExitRec ? 0 : IEM_CPUMCTX_EXTRN_MUST_MASK)
     2709                                                     | CPUMCTX_EXTRN_ALL_MSRS | CPUMCTX_EXTRN_CR0
    25632710                                                     | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4,
    25642711                                                     "MSRs");
    25652712        if (rcStrict == VINF_SUCCESS)
    25662713        {
    2567 
    2568             /*
    2569              * Handle writes.
    2570              */
    2571             if (pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE)
     2714            if (!pExitRec)
    25722715            {
    2573                 rcStrict = CPUMSetGuestMsr(pVCpu, pMsg->MsrNumber, RT_MAKE_U64((uint32_t)pMsg->Rax, (uint32_t)pMsg->Rdx));
    2574                 Log4(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc\n",
    2575                       pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    2576                       pMsg->MsrNumber, (uint32_t)pMsg->Rax, (uint32_t)pMsg->Rdx, VBOXSTRICTRC_VAL(rcStrict) ));
    2577                 if (rcStrict == VINF_SUCCESS)
     2716                /*
     2717                 * Handle writes.
     2718                 */
     2719                if (pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE)
    25782720                {
    2579                     nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
    2580                     return VINF_SUCCESS;
     2721                    rcStrict = CPUMSetGuestMsr(pVCpu, pMsg->MsrNumber, RT_MAKE_U64((uint32_t)pMsg->Rax, (uint32_t)pMsg->Rdx));
     2722                    Log4(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc\n",
     2723                          pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2724                          pMsg->MsrNumber, (uint32_t)pMsg->Rax, (uint32_t)pMsg->Rdx, VBOXSTRICTRC_VAL(rcStrict) ));
     2725                    if (rcStrict == VINF_SUCCESS)
     2726                    {
     2727                        nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
     2728                        return VINF_SUCCESS;
     2729                    }
     2730# ifndef IN_RING3
     2731                    /* move to ring-3 and handle the trap/whatever there, as we want to LogRel this. */
     2732                    if (rcStrict == VERR_CPUM_RAISE_GP_0)
     2733                        rcStrict = VINF_CPUM_R3_MSR_WRITE;
     2734                    return rcStrict;
     2735# else
     2736                    LogRel(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc!\n",
     2737                            pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2738                            pMsg->MsrNumber, (uint32_t)pMsg->Rax, (uint32_t)pMsg->Rdx, VBOXSTRICTRC_VAL(rcStrict) ));
     2739# endif
    25812740                }
     2741                /*
     2742                 * Handle reads.
     2743                 */
     2744                else
     2745                {
     2746                    uint64_t uValue = 0;
     2747                    rcStrict = CPUMQueryGuestMsr(pVCpu, pMsg->MsrNumber, &uValue);
     2748                    Log4(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n",
     2749                          pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2750                          pMsg->MsrNumber, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     2751                    if (rcStrict == VINF_SUCCESS)
     2752                    {
     2753                        pCtx->rax = (uint32_t)uValue;
     2754                        pCtx->rdx = uValue >> 32;
     2755                        pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
     2756                        nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
     2757                        return VINF_SUCCESS;
     2758                    }
    25822759# ifndef IN_RING3
    2583                 /* move to ring-3 and handle the trap/whatever there, as we want to LogRel this. */
    2584                 if (rcStrict == VERR_CPUM_RAISE_GP_0)
    2585                     rcStrict = VINF_CPUM_R3_MSR_WRITE;
    2586                 return rcStrict;
     2760                    /* move to ring-3 and handle the trap/whatever there, as we want to LogRel this. */
     2761                    if (rcStrict == VERR_CPUM_RAISE_GP_0)
     2762                        rcStrict = VINF_CPUM_R3_MSR_READ;
     2763                    return rcStrict;
    25872764# else
    2588                 LogRel(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc!\n",
    2589                         pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    2590                         pMsg->MsrNumber, (uint32_t)pMsg->Rax, (uint32_t)pMsg->Rdx, VBOXSTRICTRC_VAL(rcStrict) ));
     2765                    LogRel(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n",
     2766                            pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2767                            pMsg->MsrNumber, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
    25912768# endif
     2769                }
    25922770            }
    2593             /*
    2594              * Handle reads.
    2595              */
    25962771            else
    25972772            {
    2598                 uint64_t uValue = 0;
    2599                 rcStrict = CPUMQueryGuestMsr(pVCpu, pMsg->MsrNumber, &uValue);
    2600                 Log4(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n",
     2773                /*
     2774                 * Handle frequent exit or something needing probing.
     2775                 */
     2776                Log4(("MsrExit/%u: %04x:%08RX64/%s: %sMSR %#08x\n",
    26012777                      pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    2602                       pMsg->MsrNumber, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
    2603                 if (rcStrict == VINF_SUCCESS)
    2604                 {
    2605                     pCtx->rax = (uint32_t)uValue;
    2606                     pCtx->rdx = uValue >> 32;
    2607                     pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
    2608                     nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
    2609                     return VINF_SUCCESS;
    2610                 }
    2611 # ifndef IN_RING3
    2612                 /* move to ring-3 and handle the trap/whatever there, as we want to LogRel this. */
    2613                 if (rcStrict == VERR_CPUM_RAISE_GP_0)
    2614                     rcStrict = VINF_CPUM_R3_MSR_READ;
     2778                      pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE ? "WR" : "RD", pMsg->MsrNumber));
     2779                rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     2780                Log4(("MsrExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     2781                      pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
     2782                      VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
    26152783                return rcStrict;
    2616 # else
    2617                 LogRel(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n",
    2618                         pVCpu->idCpu, pMsg->Header.CsSegment.Selector, pMsg->Header.Rip, nemHCWinExecStateToLogStr(&pMsg->Header),
    2619                         pMsg->MsrNumber, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
    2620 # endif
    26212784            }
    26222785        }
     
    26802843         * get CR0, CR4 and CR3.
    26812844         */
    2682         EMHistoryAddExit(pVCpu,
    2683                            pExit->MsrAccess.AccessInfo.IsWrite
    2684                          ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_WRITE)
    2685                          : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_READ),
    2686                          pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    2687 
     2845        PCEMEXITREC pExitRec = EMHistoryAddExit(pVCpu,
     2846                                                  pExit->MsrAccess.AccessInfo.IsWrite
     2847                                                ? EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_WRITE)
     2848                                                : EMEXIT_MAKE_FLAGS_AND_TYPE(EMEXIT_F_KIND_EM, EMEXITTYPE_MSR_READ),
     2849                                                pExit->VpContext.Rip + pExit->VpContext.Cs.Base, ASMReadTSC());
    26882850        nemR3WinCopyStateFromX64Header(pVCpu, pCtx, &pExit->VpContext);
    26892851        rcStrict = nemHCWinImportStateIfNeededStrict(pVCpu, NULL, pCtx,
    2690                                                        CPUMCTX_EXTRN_ALL_MSRS | CPUMCTX_EXTRN_CR0
     2852                                                     (!pExitRec ? 0 : IEM_CPUMCTX_EXTRN_MUST_MASK)
     2853                                                     | CPUMCTX_EXTRN_ALL_MSRS | CPUMCTX_EXTRN_CR0
    26912854                                                     | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4,
    26922855                                                     "MSRs");
    26932856        if (rcStrict == VINF_SUCCESS)
    26942857        {
    2695             /*
    2696              * Handle writes.
    2697              */
    2698             if (pExit->MsrAccess.AccessInfo.IsWrite)
     2858            if (!pExitRec)
    26992859            {
    2700                 rcStrict = CPUMSetGuestMsr(pVCpu, pExit->MsrAccess.MsrNumber,
    2701                                            RT_MAKE_U64((uint32_t)pExit->MsrAccess.Rax, (uint32_t)pExit->MsrAccess.Rdx));
    2702                 Log4(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc\n", pVCpu->idCpu, pExit->VpContext.Cs.Selector,
    2703                       pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext), pExit->MsrAccess.MsrNumber,
    2704                       (uint32_t)pExit->MsrAccess.Rax, (uint32_t)pExit->MsrAccess.Rdx, VBOXSTRICTRC_VAL(rcStrict) ));
    2705                 if (rcStrict == VINF_SUCCESS)
     2860                /*
     2861                 * Handle writes.
     2862                 */
     2863                if (pExit->MsrAccess.AccessInfo.IsWrite)
    27062864                {
    2707                     nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
    2708                     return VINF_SUCCESS;
     2865                    rcStrict = CPUMSetGuestMsr(pVCpu, pExit->MsrAccess.MsrNumber,
     2866                                               RT_MAKE_U64((uint32_t)pExit->MsrAccess.Rax, (uint32_t)pExit->MsrAccess.Rdx));
     2867                    Log4(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc\n", pVCpu->idCpu, pExit->VpContext.Cs.Selector,
     2868                          pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext), pExit->MsrAccess.MsrNumber,
     2869                          (uint32_t)pExit->MsrAccess.Rax, (uint32_t)pExit->MsrAccess.Rdx, VBOXSTRICTRC_VAL(rcStrict) ));
     2870                    if (rcStrict == VINF_SUCCESS)
     2871                    {
     2872                        nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
     2873                        return VINF_SUCCESS;
     2874                    }
     2875                    LogRel(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc!\n", pVCpu->idCpu,
     2876                            pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2877                            pExit->MsrAccess.MsrNumber, (uint32_t)pExit->MsrAccess.Rax, (uint32_t)pExit->MsrAccess.Rdx,
     2878                            VBOXSTRICTRC_VAL(rcStrict) ));
    27092879                }
    2710                 LogRel(("MsrExit/%u: %04x:%08RX64/%s: WRMSR %08x, %08x:%08x -> %Rrc!\n", pVCpu->idCpu,
    2711                         pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    2712                         pExit->MsrAccess.MsrNumber, (uint32_t)pExit->MsrAccess.Rax, (uint32_t)pExit->MsrAccess.Rdx,
    2713                         VBOXSTRICTRC_VAL(rcStrict) ));
     2880                /*
     2881                 * Handle reads.
     2882                 */
     2883                else
     2884                {
     2885                    uint64_t uValue = 0;
     2886                    rcStrict = CPUMQueryGuestMsr(pVCpu, pExit->MsrAccess.MsrNumber, &uValue);
     2887                    Log4(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n", pVCpu->idCpu,
     2888                          pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2889                          pExit->MsrAccess.MsrNumber, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     2890                    if (rcStrict == VINF_SUCCESS)
     2891                    {
     2892                        pCtx->rax = (uint32_t)uValue;
     2893                        pCtx->rdx = uValue >> 32;
     2894                        pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
     2895                        nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
     2896                        return VINF_SUCCESS;
     2897                    }
     2898                    LogRel(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n", pVCpu->idCpu, pExit->VpContext.Cs.Selector,
     2899                            pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext), pExit->MsrAccess.MsrNumber,
     2900                            uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     2901                }
    27142902            }
    2715             /*
    2716              * Handle reads.
    2717              */
    27182903            else
    27192904            {
    2720                 uint64_t uValue = 0;
    2721                 rcStrict = CPUMQueryGuestMsr(pVCpu, pExit->MsrAccess.MsrNumber, &uValue);
    2722                 Log4(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n", pVCpu->idCpu,
    2723                       pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
    2724                       pExit->MsrAccess.MsrNumber, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
    2725                 if (rcStrict == VINF_SUCCESS)
    2726                 {
    2727                     pCtx->rax = (uint32_t)uValue;
    2728                     pCtx->rdx = uValue >> 32;
    2729                     pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RDX);
    2730                     nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pExit->VpContext);
    2731                     return VINF_SUCCESS;
    2732                 }
    2733                 LogRel(("MsrExit/%u: %04x:%08RX64/%s: RDMSR %08x -> %08RX64 / %Rrc\n", pVCpu->idCpu, pExit->VpContext.Cs.Selector,
    2734                         pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext), pExit->MsrAccess.MsrNumber,
    2735                         uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     2905                /*
     2906                 * Handle frequent exit or something needing probing.
     2907                 */
     2908                Log4(("MsrExit/%u: %04x:%08RX64/%s: %sMSR %#08x\n",
     2909                      pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2910                      pExit->MsrAccess.AccessInfo.IsWrite ? "WR" : "RD", pExit->MsrAccess.MsrNumber));
     2911                rcStrict = EMHistoryExec(pVCpu, pExitRec, 0);
     2912                Log4(("MsrExit/%u: %04x:%08RX64/%s: EMHistoryExec -> %Rrc + %04x:%08RX64\n",
     2913                      pVCpu->idCpu, pExit->VpContext.Cs.Selector, pExit->VpContext.Rip, nemR3WinExecStateToLogStr(&pExit->VpContext),
     2914                      VBOXSTRICTRC_VAL(rcStrict), pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip));
     2915                return rcStrict;
    27362916            }
    27372917        }
     
    32843464                Assert(pMsg->Header.PayloadSize == sizeof(pMsg->X64CpuIdIntercept));
    32853465                STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatExitCpuId);
    3286                 return nemHCWinHandleMessageCpuId(pVCpu, &pMsg->X64CpuIdIntercept, pCtx);
     3466                return nemHCWinHandleMessageCpuId(pVM, pVCpu, &pMsg->X64CpuIdIntercept, pGVCpu);
    32873467
    32883468            case HvMessageTypeX64MsrIntercept:
     
    33693549        case WHvRunVpExitReasonX64Cpuid:
    33703550            STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatExitCpuId);
    3371             return nemR3WinHandleExitCpuId(pVM, pVCpu, pExit, pCtx);
     3551            return nemR3WinHandleExitCpuId(pVM, pVCpu, pExit);
    33723552
    33733553        case WHvRunVpExitReasonX64MsrAccess:
  • trunk/src/VBox/VMM/VMMR3/NEMR3.cpp

    r72555 r72575  
    345345        case NEMEXITTYPE_XCPT_BP:                       return "NEM #BP";
    346346        case NEMEXITTYPE_CANCELED:                      return "NEM canceled";
     347        case NEMEXITTYPE_MEMORY_ACCESS:                 return "NEM memory access";
    347348    }
    348349
  • trunk/src/VBox/VMM/include/NEMInternal.h

    r72569 r72575  
    4545 */
    4646# define NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    47 //# define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
    48 //# define NEM_WIN_USE_OUR_OWN_RUN_API
     47# define NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     48# define NEM_WIN_USE_OUR_OWN_RUN_API
    4949# if defined(NEM_WIN_USE_OUR_OWN_RUN_API) && !defined(NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS)
    5050#  error "NEM_WIN_USE_OUR_OWN_RUN_API requires NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS"
     
    122122    NEMEXITTYPE_XCPT_DB,
    123123    NEMEXITTYPE_XCPT_BP,
    124     NEMEXITTYPE_CANCELED
     124    NEMEXITTYPE_CANCELED,
     125    NEMEXITTYPE_MEMORY_ACCESS
    125126} NEMEXITTYPE;
    126127
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette