VirtualBox

Changeset 71184 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Mar 3, 2018 3:01:59 PM (7 years ago)
Author:
vboxsync
Message:

CPUM,NEM: Introduced CPUMCTX field for tracking state that's not in the structure. Made NEM/win only get/set the register it needs. New NEM runloop based on low level messages, skipping translations. bugref:9044

File:
1 edited

Legend:

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

    r71152 r71184  
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    1616 */
     17
     18
     19/*********************************************************************************************************************************
     20*   Defined Constants And Macros                                                                                                 *
     21*********************************************************************************************************************************/
     22/** Copy back a segment from hyper-V. */
     23#define NEM_WIN_COPY_BACK_SEG(a_Dst, a_Src) \
     24            do { \
     25                (a_Dst).u64Base  = (a_Src).Base; \
     26                (a_Dst).u32Limit = (a_Src).Limit; \
     27                (a_Dst).ValidSel = (a_Dst).Sel = (a_Src).Selector; \
     28                (a_Dst).Attr.u   = (a_Src).Attributes; \
     29                (a_Dst).fFlags   = CPUMSELREG_FLAGS_VALID; \
     30            } while (0)
     31
     32/** The CPUMCTX_EXTRN_XXX mask for IEM. */
     33#define NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM      CPUMCTX_EXTRN_ALL
    1734
    1835
     
    91108#ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
    92109    NOREF(pCtx);
    93     int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_EXPORT_STATE, UINT64_MAX, NULL);
     110    int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_EXPORT_STATE, 0, NULL);
    94111    AssertLogRelRCReturn(rc, rc);
    95112    return rc;
     
    389406
    390407
    391 NEM_TMPL_STATIC int nemHCWinCopyStateFromHyperV(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
     408NEM_TMPL_STATIC int nemHCWinCopyStateFromHyperV(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, uint64_t fWhat)
    392409{
    393410#ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     411    /* See NEMR0ImportState */
    394412    NOREF(pCtx);
    395     int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_IMPORT_STATE, UINT64_MAX, NULL);
     413    int rc = VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_IMPORT_STATE, fWhat, NULL);
    396414    if (RT_SUCCESS(rc))
    397415        return rc;
     
    552570            do { \
    553571                Assert(aenmNames[a_idx] == a_enmName); \
    554                 (a_SReg).u64Base  = aValues[a_idx].Segment.Base; \
    555                 (a_SReg).u32Limit = aValues[a_idx].Segment.Limit; \
    556                 (a_SReg).ValidSel = (a_SReg).Sel = aValues[a_idx].Segment.Selector; \
    557                 (a_SReg).Attr.u   = aValues[a_idx].Segment.Attributes; \
    558                 (a_SReg).fFlags   = CPUMSELREG_FLAGS_VALID; \
     572                NEM_WIN_COPY_BACK_SEG(a_SReg, aValues[a_idx]); \
    559573            } while (0)
    560574        COPY_BACK_SEG(18, WHvX64RegisterEs,   pCtx->es);
     
    740754        /// @todo WHvRegisterPendingEvent1
    741755
     756        pCtx->fExtrn = 0;
    742757
    743758        if (fMaybeChangedMode)
     
    792807
    793808#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
    794 
    795809# ifdef IN_RING3 /* hopefully not needed in ring-0, as we'd need KTHREADs and KeAlertThread. */
    796810/**
     
    851865}
    852866# endif /* IN_RING3 */
    853 
    854 
    855 /**
    856  * Fills in WHV_VP_EXIT_CONTEXT from HV_X64_INTERCEPT_MESSAGE_HEADER.
    857  */
    858 DECLINLINE(void) nemHCWinConvertX64MsgHdrToVpExitCtx(HV_X64_INTERCEPT_MESSAGE_HEADER const *pHdr, WHV_VP_EXIT_CONTEXT *pCtx)
    859 {
    860     pCtx->ExecutionState.AsUINT16   = pHdr->ExecutionState.AsUINT16;
    861     pCtx->InstructionLength         = pHdr->InstructionLength;
    862     pCtx->Cs.Base                   = pHdr->CsSegment.Base;
    863     pCtx->Cs.Limit                  = pHdr->CsSegment.Limit;
    864     pCtx->Cs.Selector               = pHdr->CsSegment.Selector;
    865     pCtx->Cs.Attributes             = pHdr->CsSegment.Attributes;
    866     pCtx->Rip                       = pHdr->Rip;
    867     pCtx->Rflags                    = pHdr->Rflags;
    868 }
    869 
    870 
    871 /**
    872  * Convert hyper-V exit message to the WinHvPlatform structures.
    873  *
    874  * @returns VBox status code
    875  * @param   pMsgHdr         The message to convert.
    876  * @param   pExitCtx        The output structure. Assumes zeroed.
    877  */
    878 NEM_TMPL_STATIC int nemHCWinRunVirtualProcessorConvertPending(HV_MESSAGE_HEADER const *pMsgHdr, WHV_RUN_VP_EXIT_CONTEXT *pExitCtx)
    879 {
    880     switch (pMsgHdr->MessageType)
    881     {
    882         case HvMessageTypeUnmappedGpa:
    883         case HvMessageTypeGpaIntercept:
    884         {
    885             PCHV_X64_MEMORY_INTERCEPT_MESSAGE pMemMsg = (PCHV_X64_MEMORY_INTERCEPT_MESSAGE)(pMsgHdr + 1);
    886             Assert(pMsgHdr->PayloadSize == RT_UOFFSETOF(HV_X64_MEMORY_INTERCEPT_MESSAGE, DsSegment));
    887 
    888             pExitCtx->ExitReason                            = WHvRunVpExitReasonMemoryAccess;
    889             nemHCWinConvertX64MsgHdrToVpExitCtx(&pMemMsg->Header, &pExitCtx->MemoryAccess.VpContext);
    890             pExitCtx->MemoryAccess.InstructionByteCount     = pMemMsg->InstructionByteCount;
    891             ((uint64_t *)pExitCtx->MemoryAccess.InstructionBytes)[0] = ((uint64_t const *)pMemMsg->InstructionBytes)[0];
    892             ((uint64_t *)pExitCtx->MemoryAccess.InstructionBytes)[1] = ((uint64_t const *)pMemMsg->InstructionBytes)[1];
    893 
    894             pExitCtx->MemoryAccess.AccessInfo.AccessType    = pMemMsg->Header.InterceptAccessType;
    895             pExitCtx->MemoryAccess.AccessInfo.GpaUnmapped   = pMsgHdr->MessageType == HvMessageTypeUnmappedGpa;
    896             pExitCtx->MemoryAccess.AccessInfo.GvaValid      = pMemMsg->MemoryAccessInfo.GvaValid;
    897             pExitCtx->MemoryAccess.AccessInfo.Reserved      = pMemMsg->MemoryAccessInfo.Reserved;
    898             pExitCtx->MemoryAccess.Gpa                      = pMemMsg->GuestPhysicalAddress;
    899             pExitCtx->MemoryAccess.Gva                      = pMemMsg->GuestVirtualAddress;
    900             return VINF_SUCCESS;
    901         }
    902 
    903         case HvMessageTypeX64IoPortIntercept:
    904         {
    905             PCHV_X64_IO_PORT_INTERCEPT_MESSAGE pPioMsg= (PCHV_X64_IO_PORT_INTERCEPT_MESSAGE)(pMsgHdr + 1);
    906             Assert(pMsgHdr->PayloadSize == sizeof(*pPioMsg));
    907 
    908             pExitCtx->ExitReason                            = WHvRunVpExitReasonX64IoPortAccess;
    909             nemHCWinConvertX64MsgHdrToVpExitCtx(&pPioMsg->Header, &pExitCtx->IoPortAccess.VpContext);
    910             pExitCtx->IoPortAccess.InstructionByteCount     = pPioMsg->InstructionByteCount;
    911             ((uint64_t *)pExitCtx->IoPortAccess.InstructionBytes)[0] = ((uint64_t const *)pPioMsg->InstructionBytes)[0];
    912             ((uint64_t *)pExitCtx->IoPortAccess.InstructionBytes)[1] = ((uint64_t const *)pPioMsg->InstructionBytes)[1];
    913 
    914             pExitCtx->IoPortAccess.AccessInfo.IsWrite       = pPioMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE;
    915             pExitCtx->IoPortAccess.AccessInfo.AccessSize    = pPioMsg->AccessInfo.AccessSize;
    916             pExitCtx->IoPortAccess.AccessInfo.StringOp      = pPioMsg->AccessInfo.StringOp;
    917             pExitCtx->IoPortAccess.AccessInfo.RepPrefix     = pPioMsg->AccessInfo.RepPrefix;
    918             pExitCtx->IoPortAccess.AccessInfo.Reserved      = pPioMsg->AccessInfo.Reserved;
    919             pExitCtx->IoPortAccess.PortNumber               = pPioMsg->PortNumber;
    920             pExitCtx->IoPortAccess.Rax                      = pPioMsg->Rax;
    921             pExitCtx->IoPortAccess.Rcx                      = pPioMsg->Rcx;
    922             pExitCtx->IoPortAccess.Rsi                      = pPioMsg->Rsi;
    923             pExitCtx->IoPortAccess.Rdi                      = pPioMsg->Rdi;
    924             pExitCtx->IoPortAccess.Ds.Base                  = pPioMsg->DsSegment.Base;
    925             pExitCtx->IoPortAccess.Ds.Limit                 = pPioMsg->DsSegment.Limit;
    926             pExitCtx->IoPortAccess.Ds.Selector              = pPioMsg->DsSegment.Selector;
    927             pExitCtx->IoPortAccess.Ds.Attributes            = pPioMsg->DsSegment.Attributes;
    928             pExitCtx->IoPortAccess.Es.Base                  = pPioMsg->EsSegment.Base;
    929             pExitCtx->IoPortAccess.Es.Limit                 = pPioMsg->EsSegment.Limit;
    930             pExitCtx->IoPortAccess.Es.Selector              = pPioMsg->EsSegment.Selector;
    931             pExitCtx->IoPortAccess.Es.Attributes            = pPioMsg->EsSegment.Attributes;
    932             return VINF_SUCCESS;
    933         }
    934 
    935         case HvMessageTypeX64Halt:
    936         {
    937             PCHV_X64_HALT_MESSAGE pHaltMsg = (PCHV_X64_HALT_MESSAGE)(pMsgHdr + 1);
    938             AssertMsg(pHaltMsg->u64Reserved == 0, ("HALT reserved: %#RX64\n", pHaltMsg->u64Reserved));
    939             pExitCtx->ExitReason = WHvRunVpExitReasonX64Halt;
    940             return VINF_SUCCESS;
    941         }
    942 
    943         case HvMessageTypeX64InterruptWindow:
    944             AssertLogRelMsgFailedReturn(("Message type %#x not implemented!\n", pMsgHdr->MessageType), VERR_INTERNAL_ERROR_2);
    945 
    946         case HvMessageTypeInvalidVpRegisterValue:
    947         case HvMessageTypeUnrecoverableException:
    948         case HvMessageTypeUnsupportedFeature:
    949         case HvMessageTypeTlbPageSizeMismatch:
    950             AssertLogRelMsgFailedReturn(("Message type %#x not implemented!\n", pMsgHdr->MessageType), VERR_INTERNAL_ERROR_2);
    951 
    952         case HvMessageTypeX64MsrIntercept:
    953         case HvMessageTypeX64CpuidIntercept:
    954         case HvMessageTypeX64ExceptionIntercept:
    955         case HvMessageTypeX64ApicEoi:
    956         case HvMessageTypeX64LegacyFpError:
    957         case HvMessageTypeX64RegisterIntercept:
    958         case HvMessageTypeApicEoi:
    959         case HvMessageTypeFerrAsserted:
    960         case HvMessageTypeEventLogBufferComplete:
    961         case HvMessageTimerExpired:
    962             AssertLogRelMsgFailedReturn(("Unexpected message type #x!\n", pMsgHdr->MessageType), VERR_INTERNAL_ERROR_2);
    963 
    964         default:
    965             AssertLogRelMsgFailedReturn(("Unknown message type #x!\n", pMsgHdr->MessageType), VERR_INTERNAL_ERROR_2);
    966     }
    967 }
    968 
    969 
    970 /**
    971  * Our own WHvRunVirtualProcessor that can later be moved to ring-0.
    972  *
    973  * This is an experiment only.
    974  *
    975  * @returns VBox status code.
    976  * @param   pVM             The cross context VM structure.
    977  * @param   pVCpu           The cross context virtual CPU structure of the
    978  *                          calling EMT.
    979  * @param   pExitCtx        Where to return exit information.
    980  * @param   cbExitCtx       Size of the exit information area.
    981  */
    982 NEM_TMPL_STATIC int nemHCWinRunVirtualProcessor(PVM pVM, PVMCPU pVCpu, WHV_RUN_VP_EXIT_CONTEXT *pExitCtx, size_t cbExitCtx)
    983 {
    984     RT_BZERO(pExitCtx, cbExitCtx);
    985 
    986     /*
    987      * Tell the CPU to execute stuff if we haven't got a pending message.
    988      */
    989     VID_MESSAGE_MAPPING_HEADER volatile *pMappingHeader = (VID_MESSAGE_MAPPING_HEADER volatile *)pVCpu->nem.s.pvMsgSlotMapping;
    990     uint32_t                             fHandleAndGetFlags;
    991     if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED))
    992     {
    993         uint8_t const bMsgState = pVCpu->nem.s.bMsgState;
    994         if (bMsgState == NEM_WIN_MSG_STATE_PENDING_MSG)
    995         {
    996             Assert(pMappingHeader->enmVidMsgType == VidMessageHypervisorMessage);
    997             fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE | VID_MSHAGN_F_HANDLE_MESSAGE;
    998             Log8(("nemHCWinRunVirtualProcessor: #1: msg pending, no need to start CPU (cpu state %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    999         }
    1000         else if (bMsgState != NEM_WIN_MSG_STATE_STARTED)
    1001         {
    1002             if (bMsgState == NEM_WIN_MSG_STATE_PENDING_STOP_AND_MSG)
    1003             {
    1004                 Log8(("nemHCWinRunVirtualProcessor: #0: pending stop+message (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    1005                 /* ACK the pending message and get the stop message. */
    1006                 BOOL fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
    1007                                                                  VID_MSHAGN_F_HANDLE_MESSAGE | VID_MSHAGN_F_GET_NEXT_MESSAGE, 5000);
    1008                 AssertLogRelMsg(fWait, ("dwErr=%u (%#x) rcNt=%#x\n", RTNtLastErrorValue(), RTNtLastErrorValue(), RTNtLastStatusValue()));
    1009 
    1010                 /* ACK the stop message. */
    1011                 fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
    1012                                                             VID_MSHAGN_F_HANDLE_MESSAGE, 5000);
    1013                 AssertLogRelMsg(fWait, ("dwErr=%u (%#x) rcNt=%#x\n", RTNtLastErrorValue(), RTNtLastErrorValue(), RTNtLastStatusValue()));
    1014 
    1015                 pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STOPPED;
    1016             }
    1017 
    1018             Log8(("nemHCWinRunVirtualProcessor: #1: starting CPU (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    1019             if (g_pfnVidStartVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu))
    1020                 pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STARTED;
    1021             else
    1022             {
    1023                 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM);
    1024                 AssertLogRelMsgFailedReturn(("VidStartVirtualProcessor failed for CPU #%u: rcNt=%#x dwErr=%u\n",
    1025                                              pVCpu->idCpu, RTNtLastStatusValue(), RTNtLastErrorValue()),
    1026                                             VERR_INTERNAL_ERROR_3);
    1027             }
    1028             fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE;
    1029         }
    1030         else
    1031         {
    1032             /* This shouldn't happen. */
    1033             fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE;
    1034             Log8(("nemHCWinRunVirtualProcessor: #1: NO MSG PENDING! No need to start CPU (cpu state %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    1035         }
    1036     }
    1037     else
    1038     {
    1039         Log8(("nemHCWinRunVirtualProcessor: #1: state=%u -> canceled (cpu status %u)\n",
    1040               VMCPU_GET_STATE(pVCpu), nemHCWinCpuGetRunningStatus(pVCpu)));
    1041         pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
    1042         return VINF_SUCCESS;
    1043     }
    1044 
    1045     /*
    1046      * Wait for it to stop and give us a reason to work with.
    1047      */
    1048     uint32_t cMillies = 5000; // Starting low so we can experiment without getting stuck.
    1049     for (;;)
    1050     {
    1051         if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM_WAIT, VMCPUSTATE_STARTED_EXEC_NEM))
    1052         {
    1053             Log8(("nemHCWinRunVirtualProcessor: #2: Waiting %#x (cpu status %u)...\n",
    1054                   fHandleAndGetFlags, nemHCWinCpuGetRunningStatus(pVCpu)));
    1055             BOOL fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
    1056                                                              fHandleAndGetFlags, cMillies);
    1057             if (fWait)
    1058             {
    1059                 /* Not sure yet, but we have to check whether there is anything pending
    1060                    and retry if there isn't. */
    1061                 VID_MESSAGE_TYPE const enmVidMsgType = pMappingHeader->enmVidMsgType;
    1062                 if (enmVidMsgType == VidMessageHypervisorMessage)
    1063                 {
    1064                     if (!VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_WAIT))
    1065                         VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
    1066                     Log8(("nemHCWinRunVirtualProcessor: #3: wait succeeded: %#x / %#x (cpu status %u)\n",
    1067                           enmVidMsgType, ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType,
    1068                           nemHCWinCpuGetRunningStatus(pVCpu) ));
    1069                     pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_PENDING_MSG;
    1070                     return nemHCWinRunVirtualProcessorConvertPending((HV_MESSAGE_HEADER const *)(pMappingHeader + 1), pExitCtx);
    1071                 }
    1072 
    1073                 /* This shouldn't happen, and I think its wrong. */
    1074                 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED_EXEC_NEM_WAIT);
    1075 #ifdef DEBUG_bird
    1076                 __debugbreak();
    1077 #endif
    1078                 Log8(("nemHCWinRunVirtualProcessor: #3: wait succeeded, but nothing pending: %#x / %#x (cpu status %u)\n",
    1079                       enmVidMsgType, ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemHCWinCpuGetRunningStatus(pVCpu) ));
    1080                 pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STARTED;
    1081                 AssertLogRelMsgReturnStmt(enmVidMsgType == VidMessageStopRequestComplete,
    1082                                           ("enmVidMsgType=%#x\n", enmVidMsgType),
    1083                                           g_pfnVidStopVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu),
    1084                                           VERR_INTERNAL_ERROR_3);
    1085                 fHandleAndGetFlags &= ~VID_MSHAGN_F_HANDLE_MESSAGE;
    1086             }
    1087             else
    1088             {
    1089                 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED_EXEC_NEM_WAIT);
    1090 
    1091                 /* Note! VID.SYS merges STATUS_ALERTED and STATUS_USER_APC into STATUS_TIMEOUT. */
    1092                 DWORD const dwErr = RTNtLastErrorValue();
    1093                 AssertLogRelMsgReturnStmt(   dwErr == STATUS_TIMEOUT
    1094                                           || dwErr == STATUS_ALERTED || dwErr == STATUS_USER_APC, /* just in case */
    1095                                           ("dwErr=%u (%#x) (cpu status %u)\n", dwErr, dwErr, nemHCWinCpuGetRunningStatus(pVCpu)),
    1096                                           g_pfnVidStopVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu),
    1097                                           VERR_INTERNAL_ERROR_3);
    1098                 Log8(("nemHCWinRunVirtualProcessor: #3: wait timed out (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    1099                 pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STARTED;
    1100                 fHandleAndGetFlags &= ~VID_MSHAGN_F_HANDLE_MESSAGE;
    1101             }
    1102         }
    1103         else
    1104         {
    1105             /*
    1106              * State changed and we need to return.
    1107              *
    1108              * We must ensure that the processor is not running while we
    1109              * return, and that can be a bit complicated.
    1110              */
    1111             Log8(("nemHCWinRunVirtualProcessor: #4: state changed to %u (cpu status %u)\n",
    1112                   VMCPU_GET_STATE(pVCpu), nemHCWinCpuGetRunningStatus(pVCpu) ));
    1113             VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
    1114 
    1115             /* If we haven't marked the pervious message as handled, simply return
    1116                without doing anything special. */
    1117             if (fHandleAndGetFlags & VID_MSHAGN_F_HANDLE_MESSAGE)
    1118             {
    1119                 Log8(("nemHCWinRunVirtualProcessor: #5: Didn't resume previous message.\n"));
    1120                 pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_PENDING_MSG;
    1121                 pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
    1122                 return VINF_SUCCESS;
    1123             }
    1124 
    1125             /* The processor is running, so try stop it. */
    1126             BOOL fStop = g_pfnVidStopVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu);
    1127             if (fStop)
    1128             {
    1129                 Log8(("nemHCWinRunVirtualProcessor: #5: Stopping CPU succeeded (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    1130                 pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STOPPED;
    1131                 pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
    1132                 return VINF_SUCCESS;
    1133             }
    1134 
    1135             /* Dang, the CPU stopped by itself with a message pending. */
    1136             DWORD dwErr = RTNtLastErrorValue();
    1137             Log8(("nemHCWinRunVirtualProcessor: #5: Stopping CPU failed (%u/%#x) - cpu status %u\n",
    1138                   dwErr, dwErr, nemHCWinCpuGetRunningStatus(pVCpu) ));
    1139             pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
    1140             AssertLogRelMsgReturn(dwErr == ERROR_VID_STOP_PENDING, ("dwErr=%#u\n", dwErr), VERR_INTERNAL_ERROR_3);
    1141 
    1142             /* Get the pending message. */
    1143             BOOL fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
    1144                                                              VID_MSHAGN_F_GET_NEXT_MESSAGE, 5000);
    1145             AssertLogRelMsgReturn(fWait, ("error=%#u\n", RTNtLastErrorValue()), VERR_INTERNAL_ERROR_3);
    1146 
    1147             VID_MESSAGE_TYPE const enmVidMsgType = pMappingHeader->enmVidMsgType;
    1148             if (enmVidMsgType == VidMessageHypervisorMessage)
    1149             {
    1150                 Log8(("nemHCWinRunVirtualProcessor: #6: wait succeeded: %#x / %#x (cpu status %u)\n", enmVidMsgType,
    1151                       ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemHCWinCpuGetRunningStatus(pVCpu) ));
    1152                 pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_PENDING_STOP_AND_MSG;
    1153                 return nemHCWinRunVirtualProcessorConvertPending((HV_MESSAGE_HEADER const *)(pMappingHeader + 1), pExitCtx);
    1154             }
    1155 
    1156             /* ACK the stop message, if that's what it is.  Don't think we'll ever get here. */
    1157             Log8(("nemHCWinRunVirtualProcessor: #6b: wait succeeded: %#x / %#x (cpu status %u)\n", enmVidMsgType,
    1158                   ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemHCWinCpuGetRunningStatus(pVCpu) ));
    1159             AssertLogRelMsgReturn(enmVidMsgType == VidMessageStopRequestComplete, ("enmVidMsgType=%#x\n", enmVidMsgType),
    1160                                   VERR_INTERNAL_ERROR_3);
    1161             fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
    1162                                                         VID_MSHAGN_F_HANDLE_MESSAGE, 5000);
    1163             AssertLogRelMsgReturn(fWait, ("dwErr=%#u\n", RTNtLastErrorValue()), VERR_INTERNAL_ERROR_3);
    1164 
    1165             pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STOPPED;
    1166             pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
    1167             return VINF_SUCCESS;
    1168         }
    1169 
    1170         /** @todo check flags and stuff? */
    1171     }
    1172 }
    1173 
    1174867#endif /* NEM_WIN_USE_OUR_OWN_RUN_API */
     868
    1175869
    1176870#ifdef LOG_ENABLED
     
    1234928 * @param   pExitCtx        The exit context.
    1235929 */
    1236 DECLINLINE(void) nemHCWinAdvanceGuestRipAndClearRF(PVMCPU pVCpu, PCPUMCTX pCtx, WHV_VP_EXIT_CONTEXT const *pExitCtx)
    1237 {
     930DECLINLINE(void) nemHCWinAdvanceGuestRipAndClearRF(PVMCPU pVCpu, PCPUMCTX pCtx, HV_X64_INTERCEPT_MESSAGE_HEADER const *pMsgHdr)
     931{
     932    Assert(!(pCtx->fExtrn & (CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS)));
     933
    1238934    /* Advance the RIP. */
    1239     Assert(pExitCtx->InstructionLength > 0 && pExitCtx->InstructionLength < 16);
    1240     pCtx->rip += pExitCtx->InstructionLength;
     935    Assert(pMsgHdr->InstructionLength > 0 && pMsgHdr->InstructionLength < 16);
     936    pCtx->rip += pMsgHdr->InstructionLength;
    1241937    pCtx->rflags.Bits.u1RF = 0;
    1242938
     
    14761172}
    14771173
    1478 
    1479 #if 0 /* later */
    1480 NEM_TMPL_STATIC nemHCWinRunGC(PVM pVM, PVMCPU pVCpu)
    1481 {
     1174#ifdef IN_RING3
     1175
     1176/**
     1177 * Copies register state from the X64 intercept message header.
     1178 *
     1179 * ASSUMES no state copied yet.
     1180 *
     1181 * @param   pCtx            The registe rcontext.
     1182 * @param   pHdr            The X64 intercept message header.
     1183 */
     1184DECLINLINE(void) nemHCWinCopyStateFromX64Header(PCPUMCTX pCtx, HV_X64_INTERCEPT_MESSAGE_HEADER const *pHdr)
     1185{
     1186    Assert(    (pCtx->fExtrn & (CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CS))
     1187            ==                 (CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CS));
     1188    NEM_WIN_COPY_BACK_SEG(pCtx->cs, pHdr->CsSegment);
     1189    pCtx->rip    = pHdr->Rip;
     1190    pCtx->rflags.u = pHdr->Rflags;
     1191    pCtx->fExtrn &= ~(CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_CS);
     1192}
     1193
     1194
     1195/**
     1196 * Deals with memory intercept message.
     1197 *
     1198 * @returns Strict VBox status code.
     1199 * @param   pVM             The cross context VM structure.
     1200 * @param   pVCpu           The cross context per CPU structure.
     1201 * @param   pMsg            The message.
     1202 * @param   pCtx            The register context.
     1203 */
     1204NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleMessageMemory(PVM pVM, PVMCPU pVCpu, HV_X64_MEMORY_INTERCEPT_MESSAGE const *pMsg,
     1205                                                         PCPUMCTX pCtx)
     1206{
     1207    /*
     1208     * Whatever we do, we must clear pending event ejection upon resume.
     1209     */
     1210    if (pMsg->Header.ExecutionState.InterruptionPending)
     1211        pCtx->fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_MASK;
     1212
     1213    /*
     1214     * Ask PGM for information about the given GCPhys.  We need to check if we're
     1215     * out of sync first.
     1216     */
     1217    NEMHCWINHMACPCCSTATE State = { pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE, false, false };
     1218    PGMPHYSNEMPAGEINFO   Info;
     1219    int rc = PGMPhysNemPageInfoChecker(pVM, pVCpu, pMsg->GuestPhysicalAddress, State.fWriteAccess, &Info,
     1220                                       nemHCWinHandleMemoryAccessPageCheckerCallback, &State);
     1221    if (RT_SUCCESS(rc))
     1222    {
     1223        if (Info.fNemProt & (  pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE
     1224                             ? NEM_PAGE_PROT_WRITE : NEM_PAGE_PROT_READ))
     1225        {
     1226            if (State.fCanResume)
     1227            {
     1228                Log4(("MemExit: %RGp (=>%RHp) %s fProt=%u%s%s%s; restarting (%s)\n",
     1229                      pMsg->GuestPhysicalAddress, Info.HCPhys, g_apszPageStates[Info.u2NemState], Info.fNemProt,
     1230                      Info.fHasHandlers ? " handlers" : "", Info.fZeroPage    ? " zero-pg" : "",
     1231                      State.fDidSomething ? "" : " no-change", g_apszWHvMemAccesstypes[pMsg->Header.InterceptAccessType]));
     1232                return VINF_SUCCESS;
     1233            }
     1234        }
     1235        Log4(("MemExit: %RGp (=>%RHp) %s fProt=%u%s%s%s; emulating (%s)\n",
     1236              pMsg->GuestPhysicalAddress, Info.HCPhys, g_apszPageStates[Info.u2NemState], Info.fNemProt,
     1237              Info.fHasHandlers ? " handlers" : "", Info.fZeroPage    ? " zero-pg" : "",
     1238              State.fDidSomething ? "" : " no-change", g_apszWHvMemAccesstypes[pMsg->Header.InterceptAccessType]));
     1239    }
     1240    else
     1241        Log4(("MemExit: %RGp rc=%Rrc%s; emulating (%s)\n", pMsg->GuestPhysicalAddress, rc,
     1242              State.fDidSomething ? " modified-backing" : "", g_apszWHvMemAccesstypes[pMsg->Header.InterceptAccessType]));
     1243
     1244    /*
     1245     * Emulate the memory access, either access handler or special memory.
     1246     */
     1247    nemHCWinCopyStateFromX64Header(pCtx, &pMsg->Header);
     1248    rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     1249    AssertRCReturn(rc, rc);
     1250
     1251    VBOXSTRICTRC rcStrict;
     1252    if (pMsg->InstructionByteCount > 0)
     1253        rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(pCtx), pMsg->Header.Rip,
     1254                                                pMsg->InstructionBytes, pMsg->InstructionByteCount);
     1255    else
     1256        rcStrict = IEMExecOne(pVCpu);
     1257    /** @todo do we need to do anything wrt debugging here?   */
     1258    return rcStrict;
     1259
     1260}
     1261
     1262
     1263/**
     1264 * Deals with I/O port intercept message.
     1265 *
     1266 * @returns Strict VBox status code.
     1267 * @param   pVM             The cross context VM structure.
     1268 * @param   pVCpu           The cross context per CPU structure.
     1269 * @param   pMsg            The message.
     1270 */
     1271NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleMessageIoPort(PVM pVM, PVMCPU pVCpu, HV_X64_IO_PORT_INTERCEPT_MESSAGE const *pMsg,
     1272                                                         PCPUMCTX pCtx)
     1273{
     1274    Assert(   pMsg->AccessInfo.AccessSize == 1
     1275           || pMsg->AccessInfo.AccessSize == 2
     1276           || pMsg->AccessInfo.AccessSize == 4);
     1277
     1278    /*
     1279     * Whatever we do, we must clear pending event ejection upon resume.
     1280     */
     1281    if (pMsg->Header.ExecutionState.InterruptionPending)
     1282        pCtx->fExtrn &= ~CPUMCTX_EXTRN_NEM_WIN_MASK;
     1283
     1284    VBOXSTRICTRC rcStrict;
     1285    if (!pMsg->AccessInfo.StringOp)
     1286    {
     1287        /*
     1288         * Simple port I/O.
     1289         */
     1290        static uint32_t const s_fAndMask[8] =
     1291        {   UINT32_MAX, UINT32_C(0xff), UINT32_C(0xffff), UINT32_MAX,   UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX   };
     1292        uint32_t const        fAndMask      = s_fAndMask[pMsg->AccessInfo.AccessSize];
     1293        if (pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE)
     1294        {
     1295            rcStrict = IOMIOPortWrite(pVM, pVCpu, pMsg->PortNumber, (uint32_t)pMsg->Rax & fAndMask, pMsg->AccessInfo.AccessSize);
     1296            Log4(("IOExit: %04x:%08RX64: OUT %#x, %#x LB %u rcStrict=%Rrc\n", pMsg->Header.CsSegment.Selector, pMsg->Header.Rip,
     1297                  pMsg->PortNumber, (uint32_t)pMsg->Rax & fAndMask, pMsg->AccessInfo.AccessSize, VBOXSTRICTRC_VAL(rcStrict) ));
     1298            if (IOM_SUCCESS(rcStrict))
     1299            {
     1300                nemHCWinCopyStateFromX64Header(pCtx, &pMsg->Header);
     1301                nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
     1302            }
     1303        }
     1304        else
     1305        {
     1306            uint32_t uValue = 0;
     1307            rcStrict = IOMIOPortRead(pVM, pVCpu, pMsg->PortNumber, &uValue, pMsg->AccessInfo.AccessSize);
     1308            Log4(("IOExit: %04x:%08RX64: IN %#x LB %u -> %#x, rcStrict=%Rrc\n", pMsg->Header.CsSegment.Selector, pMsg->Header.Rip,
     1309                  pMsg->PortNumber, pMsg->AccessInfo.AccessSize, uValue, VBOXSTRICTRC_VAL(rcStrict) ));
     1310            if (IOM_SUCCESS(rcStrict))
     1311            {
     1312                if (pMsg->AccessInfo.AccessSize != 4)
     1313                    pCtx->rax = (pMsg->Rax & ~(uint64_t)fAndMask) | (uValue & fAndMask);
     1314                else
     1315                    pCtx->rax = uValue;
     1316                pCtx->fExtrn &= ~CPUMCTX_EXTRN_RAX;
     1317                Log4(("IOExit: RAX %#RX64 -> %#RX64\n", pMsg->Rax, pCtx->rax));
     1318                nemHCWinCopyStateFromX64Header(pCtx, &pMsg->Header);
     1319                nemHCWinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pMsg->Header);
     1320            }
     1321        }
     1322    }
     1323    else
     1324    {
     1325        /*
     1326         * String port I/O.
     1327         */
     1328        /** @todo Someone at Microsoft please explain how we can get the address mode
     1329         * from the IoPortAccess.VpContext.  CS.Attributes is only sufficient for
     1330         * getting the default mode, it can always be overridden by a prefix.   This
     1331         * forces us to interpret the instruction from opcodes, which is suboptimal.
     1332         * Both AMD-V and VT-x includes the address size in the exit info, at least on
     1333         * CPUs that are reasonably new.
     1334         *
     1335         * Of course, it's possible this is an undocumented and we just need to do some
     1336         * experiments to figure out how it's communicated.  Alternatively, we can scan
     1337         * the opcode bytes for possible evil prefixes.
     1338         */
     1339        nemHCWinCopyStateFromX64Header(pCtx, &pMsg->Header);
     1340        pCtx->fExtrn &= ~(  CPUMCTX_EXTRN_RAX | CPUMCTX_EXTRN_RCX | CPUMCTX_EXTRN_RDI | CPUMCTX_EXTRN_RSI
     1341                          | CPUMCTX_EXTRN_DS  | CPUMCTX_EXTRN_ES);
     1342        NEM_WIN_COPY_BACK_SEG(pCtx->ds, pMsg->DsSegment);
     1343        NEM_WIN_COPY_BACK_SEG(pCtx->es, pMsg->EsSegment);
     1344        pCtx->rax = pMsg->Rax;
     1345        pCtx->rcx = pMsg->Rcx;
     1346        pCtx->rdi = pMsg->Rdi;
     1347        pCtx->rsi = pMsg->Rsi;
     1348        int rc = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM);
     1349        AssertRCReturn(rc, rc);
     1350
     1351        Log4(("IOExit: %04x:%08RX64: %s%s %#x LB %u (emulating)\n", pMsg->Header.CsSegment.Selector, pMsg->Header.Rip,
     1352              pMsg->AccessInfo.RepPrefix ? "REP " : "",
     1353              pMsg->Header.InterceptAccessType == HV_INTERCEPT_ACCESS_WRITE ? "OUTS" : "INS",
     1354              pMsg->PortNumber, pMsg->AccessInfo.AccessSize ));
     1355        rcStrict = IEMExecOne(pVCpu);
     1356    }
     1357    if (IOM_SUCCESS(rcStrict))
     1358    {
     1359        /*
     1360         * Do debug checks.
     1361         */
     1362        if (   pMsg->Header.ExecutionState.DebugActive /** @todo Microsoft: Does DebugActive this only reflext DR7? */
     1363            || (pMsg->Header.Rflags & X86_EFL_TF)
     1364            || DBGFBpIsHwIoArmed(pVM) )
     1365        {
     1366            /** @todo Debugging. */
     1367        }
     1368    }
     1369    return rcStrict;
     1370}
     1371
     1372
     1373/**
     1374 * Handles messages (VM exits).
     1375 *
     1376 * @returns Strict VBox status code.
     1377 * @param   pVM             The cross context VM structure.
     1378 * @param   pVCpu           The cross context per CPU structure.
     1379 * @param   pMappingHeader  The message slot mapping.
     1380 * @param   pCtx            The register context.
     1381 */
     1382NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleMessage(PVM pVM, PVMCPU pVCpu, VID_MESSAGE_MAPPING_HEADER volatile *pMappingHeader,
     1383                                                   PCPUMCTX pCtx)
     1384{
     1385    if (pMappingHeader->enmVidMsgType == VidMessageHypervisorMessage)
     1386    {
     1387        AssertMsg(pMappingHeader->cbMessage == HV_MESSAGE_SIZE, ("%#x\n", pMappingHeader->cbMessage));
     1388        HV_MESSAGE const *pMsg = (HV_MESSAGE const *)(pMappingHeader + 1);
     1389        switch (pMsg->Header.MessageType)
     1390        {
     1391            case HvMessageTypeUnmappedGpa:
     1392                Assert(pMsg->Header.PayloadSize == RT_UOFFSETOF(HV_X64_MEMORY_INTERCEPT_MESSAGE, DsSegment));
     1393                return nemHCWinHandleMessageMemory(pVM, pVCpu, &pMsg->X64MemoryIntercept, pCtx);
     1394
     1395            case HvMessageTypeGpaIntercept:
     1396                Assert(pMsg->Header.PayloadSize == RT_UOFFSETOF(HV_X64_MEMORY_INTERCEPT_MESSAGE, DsSegment));
     1397                return nemHCWinHandleMessageMemory(pVM, pVCpu, &pMsg->X64MemoryIntercept, pCtx);
     1398
     1399            case HvMessageTypeX64IoPortIntercept:
     1400                Assert(pMsg->Header.PayloadSize == sizeof(pMsg->X64IoPortIntercept));
     1401                return nemHCWinHandleMessageIoPort(pVM, pVCpu, &pMsg->X64IoPortIntercept, pCtx);
     1402
     1403            case HvMessageTypeX64Halt:
     1404                return VINF_EM_HALT;
     1405
     1406            case HvMessageTypeX64InterruptWindow:
     1407                AssertLogRelMsgFailedReturn(("Message type %#x not implemented!\n", pMsg->Header.MessageType),
     1408                                            VERR_INTERNAL_ERROR_2);
     1409
     1410            case HvMessageTypeInvalidVpRegisterValue:
     1411            case HvMessageTypeUnrecoverableException:
     1412            case HvMessageTypeUnsupportedFeature:
     1413            case HvMessageTypeTlbPageSizeMismatch:
     1414                AssertLogRelMsgFailedReturn(("Message type %#x not implemented!\n", pMsg->Header.MessageType),
     1415                                            VERR_INTERNAL_ERROR_2);
     1416
     1417            case HvMessageTypeX64MsrIntercept:
     1418            case HvMessageTypeX64CpuidIntercept:
     1419            case HvMessageTypeX64ExceptionIntercept:
     1420            case HvMessageTypeX64ApicEoi:
     1421            case HvMessageTypeX64LegacyFpError:
     1422            case HvMessageTypeX64RegisterIntercept:
     1423            case HvMessageTypeApicEoi:
     1424            case HvMessageTypeFerrAsserted:
     1425            case HvMessageTypeEventLogBufferComplete:
     1426            case HvMessageTimerExpired:
     1427                AssertLogRelMsgFailedReturn(("Unexpected message on CPU #%u: #x\n", pVCpu->idCpu, pMsg->Header.MessageType),
     1428                                            VERR_INTERNAL_ERROR_2);
     1429
     1430            default:
     1431                AssertLogRelMsgFailedReturn(("Unknown message on CPU #%u: #x\n", pVCpu->idCpu, pMsg->Header.MessageType),
     1432                                            VERR_INTERNAL_ERROR_2);
     1433        }
     1434    }
     1435    else
     1436        AssertLogRelMsgFailedReturn(("Unexpected VID message type on CPU #%u: %#x LB %u\n",
     1437                                     pVCpu->idCpu, pMappingHeader->enmVidMsgType, pMappingHeader->cbMessage),
     1438                                    VERR_INTERNAL_ERROR_3);
     1439}
     1440
     1441
     1442/**
     1443 * Worker for nemHCWinRunGC that stops the execution on the way out.
     1444 *
     1445 * The CPU was running the last time we checked, no there are no messages that
     1446 * needs being marked handled/whatever.  Caller checks this.
     1447 *
     1448 * @returns rcStrict on success, error status on failure.
     1449 * @param   pVM             The cross context VM structure.
     1450 * @param   pVCpu           The cross context per CPU structure.
     1451 * @param   rcStrict        The nemHCWinRunGC return status.  This is a little
     1452 *                          bit unnecessary, except in internal error cases,
     1453 *                          since we won't need to stop the CPU if we took an
     1454 *                          exit.
     1455 * @param   pMappingHeader  The message slot mapping.
     1456 */
     1457NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinStopCpu(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict,
     1458                                             VID_MESSAGE_MAPPING_HEADER volatile *pMappingHeader)
     1459{
     1460    /*
     1461     * Try stopping the processor.  If we're lucky we manage to do this before it
     1462     * does another VM exit.
     1463     */
     1464    BOOL fRet = VidStopVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu);
     1465    if (fRet)
     1466    {
     1467        Log8(("nemHCWinStopCpu: Stopping CPU succeeded (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
     1468        return rcStrict;
     1469    }
     1470
     1471    /*
     1472     * Dang. The CPU stopped by itself and we got a couple of message to deal with.
     1473     */
     1474    DWORD dwErr = RTNtLastErrorValue();
     1475    AssertLogRelMsgReturn(dwErr == ERROR_VID_STOP_PENDING, ("dwErr=%#u\n", dwErr),
     1476                          RT_SUCCESS(rcStrict) ?  VERR_INTERNAL_ERROR_3 : rcStrict);
     1477    Log8(("nemHCWinStopCpu: Stopping CPU pending...\n"));
     1478
     1479    /*
     1480     * First message: Exit or similar.
     1481     * Note! We can safely ASSUME that rcStrict isn't an important information one.
     1482     */
     1483    BOOL fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
     1484                                                     VID_MSHAGN_F_GET_NEXT_MESSAGE, 30000 /*ms*/);
     1485    AssertLogRelMsgReturn(fWait,
     1486                          ("1st VidMessageSlotHandleAndGetNext after ERROR_VID_STOP_PENDING failed: %u\n", RTNtLastErrorValue()),
     1487                          RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR_3 : rcStrict);
     1488
     1489    /* It should be a hypervisor message and definitely not a stop request completed message. */
     1490    VID_MESSAGE_TYPE enmVidMsgType = pMappingHeader->enmVidMsgType;
     1491    AssertLogRelMsgReturn(enmVidMsgType != VidMessageStopRequestComplete,
     1492                          ("Unexpected 1st message following ERROR_VID_STOP_PENDING: %#x LB %#x\n",
     1493                           enmVidMsgType, pMappingHeader->cbMessage),
     1494                          RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR_3 : rcStrict);
     1495
     1496    VBOXSTRICTRC rcStrict2 = nemHCWinHandleMessage(pVM, pVCpu, pMappingHeader, CPUMQueryGuestCtxPtr(pVCpu));
     1497    if (rcStrict2 != VINF_SUCCESS && RT_SUCCESS(rcStrict))
     1498        rcStrict = rcStrict2;
     1499
     1500    /*
     1501     * Mark it as handled and get the stop request completed message, then mark
     1502     * that as handled too.  CPU is back into fully stopped stated then.
     1503     */
     1504    fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
     1505                                                VID_MSHAGN_F_HANDLE_MESSAGE | VID_MSHAGN_F_GET_NEXT_MESSAGE, 30000 /*ms*/);
     1506    AssertLogRelMsgReturn(fWait,
     1507                          ("2nd VidMessageSlotHandleAndGetNext after ERROR_VID_STOP_PENDING failed: %u\n", RTNtLastErrorValue()),
     1508                          RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR_3 : rcStrict);
     1509
     1510    /* It should be a stop request completed message. */
     1511    enmVidMsgType = pMappingHeader->enmVidMsgType;
     1512    AssertLogRelMsgReturn(enmVidMsgType == VidMessageStopRequestComplete,
     1513                          ("Unexpected 2nd message following ERROR_VID_STOP_PENDING: %#x LB %#x\n",
     1514                           enmVidMsgType, pMappingHeader->cbMessage),
     1515                          RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR_3 : rcStrict);
     1516
     1517    /* Mark this as handled. */
     1518    fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
     1519                                                VID_MSHAGN_F_HANDLE_MESSAGE, 30000 /*ms*/);
     1520    AssertLogRelMsgReturn(fWait,
     1521                          ("3rd VidMessageSlotHandleAndGetNext after ERROR_VID_STOP_PENDING failed: %u\n", RTNtLastErrorValue()),
     1522                          RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR_3 : rcStrict);
     1523    Log8(("nemHCWinStopCpu: Stopped the CPU (rcStrict=%Rrc)\n", VBOXSTRICTRC_VAL(rcStrict) ));
     1524    return rcStrict;
     1525}
     1526
     1527
     1528NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinRunGC(PVM pVM, PVMCPU pVCpu)
     1529{
     1530    PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
     1531    LogFlow(("nemHCWinRunGC: Entering #%u cs:rip=%04x:%08RX64 efl=%#08RX64\n", pVCpu->idCpu, pCtx->cs.Sel, pCtx->rip, pCtx->rflags));
    14821532#ifdef LOG_ENABLED
    14831533    if (LogIs3Enabled())
    1484     {
    1485         Log3(("nemR3NativeRunGC: Entering #%u\n", pVCpu->idCpu));
    1486         nemR3WinLogState(pVM, pVCpu);
    1487     }
     1534        nemHCWinLogState(pVM, pVCpu);
    14881535#endif
    14891536
     
    14941541     * everything every time.  This will be optimized later.
    14951542     */
    1496     const bool   fSingleStepping = false; /** @todo get this from somewhere. */
    1497     VBOXSTRICTRC rcStrict = VINF_SUCCESS;
     1543    VID_MESSAGE_MAPPING_HEADER volatile *pMappingHeader = (VID_MESSAGE_MAPPING_HEADER volatile *)pVCpu->nem.s.pvMsgSlotMapping;
     1544    uint32_t     cMillies           = 5000; /** @todo lower this later... */
     1545    const bool   fSingleStepping    = false; /** @todo get this from somewhere. */
     1546    VBOXSTRICTRC rcStrict           = VINF_SUCCESS;
    14981547    for (unsigned iLoop = 0;;iLoop++)
    14991548    {
    15001549        /*
    1501          * Copy the state.
     1550         * Ensure that hyper-V has the whole state.
    15021551         */
    1503         PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
    1504         int rc2 = nemHCWinCopyStateToHyperV(pVM, pVCpu, pCtx);
    1505         AssertRCBreakStmt(rc2, rcStrict = rc2);
     1552        if ((pCtx->fExtrn & (CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_NEM_WIN_MASK)) != (CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_NEM_WIN_MASK))
     1553        {
     1554            int rc2 = nemHCWinCopyStateToHyperV(pVM, pVCpu, pCtx);
     1555            AssertRCReturn(rc2, rc2);
     1556        }
    15061557
    15071558        /*
    15081559         * Run a bit.
    15091560         */
    1510         WHV_RUN_VP_EXIT_CONTEXT ExitReason;
    1511         RT_ZERO(ExitReason);
    15121561        if (   !VM_FF_IS_PENDING(pVM, VM_FF_EMT_RENDEZVOUS | VM_FF_TM_VIRTUAL_SYNC)
    15131562            && !VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
    15141563        {
    1515 #ifdef NEM_WIN_USE_OUR_OWN_RUN_API
    1516             int rc2 = nemR3WinRunVirtualProcessor(pVM, pVCpu, &ExitReason, sizeof(ExitReason));
    1517             AssertRCBreakStmt(rc2, rcStrict = rc2);
    1518 #else
    1519             Log8(("Calling WHvRunVirtualProcessor\n"));
    1520             VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED);
    1521             HRESULT hrc = WHvRunVirtualProcessor(pVM->nem.s.hPartition, pVCpu->idCpu, &ExitReason, sizeof(ExitReason));
    1522             VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM);
    1523             AssertLogRelMsgBreakStmt(SUCCEEDED(hrc),
    1524                                      ("WHvRunVirtualProcessor(%p, %u,,) -> %Rhrc (Last=%#x/%u)\n", pVM->nem.s.hPartition, pVCpu->idCpu,
    1525                                       hrc, RTNtLastStatusValue(), RTNtLastErrorValue()),
    1526                                      rcStrict = VERR_INTERNAL_ERROR);
    1527             Log2(("WHvRunVirtualProcessor -> %#x; exit code %#x (%d) (cpu status %u)\n",
    1528                   hrc, ExitReason.ExitReason, ExitReason.ExitReason, nemR3WinCpuGetRunningStatus(pVCpu) ));
     1564            if (pVCpu->nem.s.fHandleAndGetFlags)
     1565            { /* Very likely that the CPU does NOT need starting (pending msg, running). */ }
     1566            else
     1567            {
     1568                if (g_pfnVidStartVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu))
     1569                    pVCpu->nem.s.fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE;
     1570                else
     1571                    AssertLogRelMsgFailedReturn(("VidStartVirtualProcessor failed for CPU #%u: %u (%#x, rcNt=%#x)\n",
     1572                                                 pVCpu->idCpu, RTNtLastErrorValue(), RTNtLastErrorValue(), RTNtLastStatusValue()),
     1573                                                VERR_INTERNAL_ERROR_3);
     1574            }
     1575
     1576            if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED))
     1577            {
     1578                BOOL fRet = VidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
     1579                                                           pVCpu->nem.s.fHandleAndGetFlags, cMillies);
     1580                VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM);
     1581                if (fRet)
     1582                {
     1583                    /*
     1584                     * Deal with the message.
     1585                     */
     1586                    rcStrict = nemHCWinHandleMessage(pVM, pVCpu, pMappingHeader, pCtx);
     1587                    pVCpu->nem.s.fHandleAndGetFlags |= VID_MSHAGN_F_HANDLE_MESSAGE;
     1588                }
     1589                else
     1590                {
     1591                    /* VID.SYS merges STATUS_ALERTED and STATUS_USER_APC into STATUS_TIMEOUT,
     1592                       so after NtAlertThread we end up here with a STATUS_TIMEOUT.  And yeah,
     1593                       the error code conversion is into WAIT_XXX, i.e. NT status codes. */
     1594                    DWORD dwErr = GetLastError();
     1595                    if (   dwErr == STATUS_TIMEOUT
     1596                        || dwErr == STATUS_ALERTED  /* just in case */
     1597                        || dwErr == STATUS_USER_APC /* ditto */ )
     1598                        pVCpu->nem.s.fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE; /* exits are likely */
     1599                    else
     1600                        AssertLogRelMsgFailedReturn(("VidMessageSlotHandleAndGetNext failed for CPU #%u: %u (%#x, rcNt=%#x)\n",
     1601                                                     pVCpu->idCpu, dwErr, dwErr, RTNtLastStatusValue()),
     1602                                                    VERR_INTERNAL_ERROR_3);
     1603                }
     1604
     1605                /*
     1606                 * If no relevant FFs are pending, loop.
     1607                 */
     1608                if (   !VM_FF_IS_PENDING(   pVM,   !fSingleStepping ? VM_FF_HP_R0_PRE_HM_MASK    : VM_FF_HP_R0_PRE_HM_STEP_MASK)
     1609                    && !VMCPU_FF_IS_PENDING(pVCpu, !fSingleStepping ? VMCPU_FF_HP_R0_PRE_HM_MASK : VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
     1610                    continue;
     1611
     1612                /** @todo Try handle pending flags, not just return to EM loops.  Take care
     1613                 *        not to set important RCs here unless we've handled a message. */
     1614                LogFlow(("nemHCWinRunGC: returning: pending FF (%#x / %#x)\n", pVM->fGlobalForcedActions, pVCpu->fLocalForcedActions));
     1615            }
     1616            else
     1617                LogFlow(("nemHCWinRunGC: returning: canceled %d (pre exec)\n", VMCPU_GET_STATE(pVCpu) ));
     1618        }
     1619        else
     1620            LogFlow(("nemHCWinRunGC: returning: pending FF (pre exec)\n"));
     1621        break;
     1622    } /* the run loop */
     1623
     1624
     1625    /*
     1626     * If the CPU is running, make sure to stop it before we try sync back the
     1627     * state and return to EM.
     1628     */
     1629    if (pVCpu->nem.s.fHandleAndGetFlags == VID_MSHAGN_F_GET_NEXT_MESSAGE)
     1630    {
     1631        pVCpu->nem.s.fHandleAndGetFlags = 0;
     1632        rcStrict = nemHCWinStopCpu(pVM, pVCpu, rcStrict, pMappingHeader);
     1633    }
     1634
     1635    VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
     1636
     1637    if (pCtx->fExtrn & (CPUMCTX_EXTRN_ALL | (CPUMCTX_EXTRN_NEM_WIN_MASK & ~CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT)))
     1638    {
     1639        int rc2 = nemHCWinCopyStateFromHyperV(pVM, pVCpu, pCtx, CPUMCTX_EXTRN_ALL | CPUMCTX_EXTRN_NEM_WIN_MASK);
     1640        if (RT_SUCCESS(rc2))
     1641            pCtx->fExtrn = 0;
     1642        else if (RT_SUCCESS(rcStrict))
     1643            rcStrict = rc2;
     1644    }
     1645    else
     1646        pCtx->fExtrn = 0;
     1647
     1648    LogFlow(("nemHCWinRunGC: Leaving #%u cs:rip=%04x:%08RX64 efl=%#08RX64\n", pVCpu->idCpu, pCtx->cs.Sel, pCtx->rip, pCtx->rflags));
     1649    return rcStrict;
     1650}
    15291651#endif
    1530         }
    1531         else
    1532         {
    1533             LogFlow(("nemR3NativeRunGC: returning: pending FF (pre exec)\n"));
    1534             break;
    1535         }
    1536 
    1537         /*
    1538          * Copy back the state.
    1539          */
    1540         rc2 = nemR3WinCopyStateFromHyperV(pVM, pVCpu, pCtx);
    1541         AssertRCBreakStmt(rc2, rcStrict = rc2);
    1542 
    1543 #ifdef LOG_ENABLED
    1544         /*
    1545          * Do some logging.
    1546          */
    1547         if (LogIs2Enabled())
    1548             nemR3WinLogExitReason(&ExitReason);
    1549         if (LogIs3Enabled())
    1550             nemR3WinLogState(pVM, pVCpu);
    1551 #endif
    1552 
    1553 #ifdef VBOX_STRICT
    1554         /* Assert that the VpContext field makes sense. */
    1555         switch (ExitReason.ExitReason)
    1556         {
    1557             case WHvRunVpExitReasonMemoryAccess:
    1558             case WHvRunVpExitReasonX64IoPortAccess:
    1559             case WHvRunVpExitReasonX64MsrAccess:
    1560             case WHvRunVpExitReasonX64Cpuid:
    1561             case WHvRunVpExitReasonException:
    1562             case WHvRunVpExitReasonUnrecoverableException:
    1563                 Assert(   ExitReason.IoPortAccess.VpContext.InstructionLength > 0
    1564                        || (   ExitReason.ExitReason == WHvRunVpExitReasonMemoryAccess
    1565                            && ExitReason.MemoryAccess.AccessInfo.AccessType == WHvMemoryAccessExecute));
    1566                 Assert(ExitReason.IoPortAccess.VpContext.InstructionLength < 16);
    1567                 Assert(ExitReason.IoPortAccess.VpContext.ExecutionState.Cpl == CPUMGetGuestCPL(pVCpu));
    1568                 Assert(ExitReason.IoPortAccess.VpContext.ExecutionState.Cr0Pe == RT_BOOL(pCtx->cr0 & X86_CR0_PE));
    1569                 Assert(ExitReason.IoPortAccess.VpContext.ExecutionState.Cr0Am == RT_BOOL(pCtx->cr0 & X86_CR0_AM));
    1570                 Assert(ExitReason.IoPortAccess.VpContext.ExecutionState.EferLma == RT_BOOL(pCtx->msrEFER & MSR_K6_EFER_LMA));
    1571                 Assert(ExitReason.IoPortAccess.VpContext.ExecutionState.DebugActive == RT_BOOL(pCtx->dr[7] & X86_DR7_ENABLED_MASK));
    1572                 Assert(ExitReason.IoPortAccess.VpContext.ExecutionState.Reserved0 == 0);
    1573                 Assert(ExitReason.IoPortAccess.VpContext.ExecutionState.Reserved1 == 0);
    1574                 Assert(ExitReason.IoPortAccess.VpContext.Rip == pCtx->rip);
    1575                 Assert(ExitReason.IoPortAccess.VpContext.Rflags == pCtx->rflags.u);
    1576                 Assert(   ExitReason.IoPortAccess.VpContext.Cs.Base     == pCtx->cs.u64Base
    1577                        && ExitReason.IoPortAccess.VpContext.Cs.Limit    == pCtx->cs.u32Limit
    1578                        && ExitReason.IoPortAccess.VpContext.Cs.Selector == pCtx->cs.Sel);
    1579                 break;
    1580             default: break; /* shut up compiler. */
    1581         }
    1582 #endif
    1583 
    1584         /*
    1585          * Deal with the exit.
    1586          */
    1587         switch (ExitReason.ExitReason)
    1588         {
    1589             /* Frequent exits: */
    1590             case WHvRunVpExitReasonCanceled:
    1591             case WHvRunVpExitReasonAlerted:
    1592                 rcStrict = VINF_SUCCESS;
    1593                 break;
    1594 
    1595             case WHvRunVpExitReasonX64Halt:
    1596                 rcStrict = nemR3WinHandleHalt(pVM, pVCpu, pCtx);
    1597                 break;
    1598 
    1599             case WHvRunVpExitReasonMemoryAccess:
    1600                 rcStrict = nemR3WinHandleMemoryAccess(pVM, pVCpu, pCtx, &ExitReason.MemoryAccess);
    1601                 break;
    1602 
    1603             case WHvRunVpExitReasonX64IoPortAccess:
    1604                 rcStrict = nemR3WinHandleIoPortAccess(pVM, pVCpu, pCtx, &ExitReason.IoPortAccess);
    1605                 break;
    1606 
    1607             case WHvRunVpExitReasonX64InterruptWindow:
    1608                 rcStrict = nemR3WinHandleInterruptWindow(pVM, pVCpu, pCtx, &ExitReason);
    1609                 break;
    1610 
    1611             case WHvRunVpExitReasonX64MsrAccess: /* needs configuring */
    1612                 rcStrict = nemR3WinHandleMsrAccess(pVM, pVCpu, pCtx, &ExitReason);
    1613                 break;
    1614 
    1615             case WHvRunVpExitReasonX64Cpuid: /* needs configuring */
    1616                 rcStrict = nemR3WinHandleCpuId(pVM, pVCpu, pCtx, &ExitReason);
    1617                 break;
    1618 
    1619             case WHvRunVpExitReasonException: /* needs configuring */
    1620                 rcStrict = nemR3WinHandleException(pVM, pVCpu, pCtx, &ExitReason);
    1621                 break;
    1622 
    1623             /* Unlikely exits: */
    1624             case WHvRunVpExitReasonUnsupportedFeature:
    1625                 rcStrict = nemR3WinHandleUD(pVM, pVCpu, pCtx, &ExitReason);
    1626                 break;
    1627 
    1628             case WHvRunVpExitReasonUnrecoverableException:
    1629                 rcStrict = nemR3WinHandleTripleFault(pVM, pVCpu, pCtx, &ExitReason);
    1630                 break;
    1631 
    1632             case WHvRunVpExitReasonInvalidVpRegisterValue:
    1633                 rcStrict = nemR3WinHandleInvalidState(pVM, pVCpu, pCtx, &ExitReason);
    1634                 break;
    1635 
    1636             /* Undesired exits: */
    1637             case WHvRunVpExitReasonNone:
    1638             default:
    1639                 AssertLogRelMsgFailed(("Unknown ExitReason: %#x\n", ExitReason.ExitReason));
    1640                 rcStrict = VERR_INTERNAL_ERROR_3;
    1641                 break;
    1642         }
    1643         if (rcStrict != VINF_SUCCESS)
    1644         {
    1645             LogFlow(("nemR3NativeRunGC: returning: %Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    1646             break;
    1647         }
    1648 
    1649 #ifndef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    1650         /* Hack alert! */
    1651         uint32_t const cMappedPages = pVM->nem.s.cMappedPages;
    1652         if (cMappedPages < 4000)
    1653         { /* likely */ }
    1654         else
    1655         {
    1656             PGMPhysNemEnumPagesByState(pVM, pVCpu, NEM_WIN_PAGE_STATE_READABLE, nemR3WinUnmapOnePageCallback, NULL);
    1657             Log(("nemR3NativeRunGC: Unmapped all; cMappedPages=%u -> %u\n", cMappedPages, pVM->nem.s.cMappedPages));
    1658         }
    1659 #endif
    1660 
    1661         /* If any FF is pending, return to the EM loops.  That's okay for the
    1662            current sledgehammer approach. */
    1663         if (   VM_FF_IS_PENDING(   pVM,   !fSingleStepping ? VM_FF_HP_R0_PRE_HM_MASK    : VM_FF_HP_R0_PRE_HM_STEP_MASK)
    1664             || VMCPU_FF_IS_PENDING(pVCpu, !fSingleStepping ? VMCPU_FF_HP_R0_PRE_HM_MASK : VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
    1665         {
    1666             LogFlow(("nemR3NativeRunGC: returning: pending FF (%#x / %#x)\n", pVM->fGlobalForcedActions, pVCpu->fLocalForcedActions));
    1667             break;
    1668         }
    1669     }
    1670 
    1671     return rcStrict;
    1672 }
    1673 #endif /* later */
    1674 
    16751652
    16761653#endif /* IN_RING0 */
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