VirtualBox

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


Ignore:
Timestamp:
Feb 28, 2018 12:36:04 PM (7 years ago)
Author:
vboxsync
Message:

VMM/NEM/win: Refactoring... bugref:9044

Location:
trunk/src/VBox/VMM/VMMAll
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/NEMAll.cpp

    r70977 r71152  
    4141#if defined(VBOX_WITH_NATIVE_NEM) && defined(IN_RING3)
    4242    if (VM_IS_NEM_ENABLED(pVM))
    43         nemR3NativeNotifyHandlerPhysicalRegister(pVM, enmKind, GCPhys, cb);
     43        nemHCNativeNotifyHandlerPhysicalRegister(pVM, enmKind, GCPhys, cb);
    4444#else
    4545    RT_NOREF(pVM, enmKind, GCPhys, cb);
     
    5353#if defined(VBOX_WITH_NATIVE_NEM) && defined(IN_RING3)
    5454    if (VM_IS_NEM_ENABLED(pVM))
    55         nemR3NativeNotifyHandlerPhysicalDeregister(pVM, enmKind, GCPhys, cb, fRestoreAsRAM, fRestoreAsRAM2);
     55        nemHCNativeNotifyHandlerPhysicalDeregister(pVM, enmKind, GCPhys, cb, fRestoreAsRAM, fRestoreAsRAM2);
    5656#else
    5757    RT_NOREF(pVM, enmKind, GCPhys, cb, fRestoreAsRAM, fRestoreAsRAM2);
     
    6565#if defined(VBOX_WITH_NATIVE_NEM) && defined(IN_RING3)
    6666    if (VM_IS_NEM_ENABLED(pVM))
    67         nemR3NativeNotifyHandlerPhysicalModify(pVM, enmKind, GCPhysOld, GCPhysNew, cb, fRestoreAsRAM);
     67        nemHCNativeNotifyHandlerPhysicalModify(pVM, enmKind, GCPhysOld, GCPhysNew, cb, fRestoreAsRAM);
    6868#else
    6969    RT_NOREF(pVM, enmKind, GCPhysOld, GCPhysNew, cb, fRestoreAsRAM);
     
    7777    Assert(VM_IS_NEM_ENABLED(pVM));
    7878#if defined(VBOX_WITH_NATIVE_NEM) && defined(IN_RING3)
    79     return nemR3NativeNotifyPhysPageAllocated(pVM, GCPhys, HCPhys, fPageProt, enmType, pu2State);
     79    return nemHCNativeNotifyPhysPageAllocated(pVM, GCPhys, HCPhys, fPageProt, enmType, pu2State);
    8080#else
    8181    RT_NOREF(pVM, GCPhys, HCPhys, fPageProt, enmType, pu2State);
     
    8989{
    9090    Assert(VM_IS_NEM_ENABLED(pVM));
    91 #if defined(VBOX_WITH_NATIVE_NEM) && defined(IN_RING3)
    92     nemR3NativeNotifyPhysPageProtChanged(pVM, GCPhys, HCPhys, fPageProt, enmType, pu2State);
     91#if defined(VBOX_WITH_NATIVE_NEM)
     92    nemHCNativeNotifyPhysPageProtChanged(pVM, GCPhys, HCPhys, fPageProt, enmType, pu2State);
    9393#else
    9494    RT_NOREF(pVM, GCPhys, HCPhys, fPageProt, enmType, pu2State);
     
    101101{
    102102    Assert(VM_IS_NEM_ENABLED(pVM));
    103 #if defined(VBOX_WITH_NATIVE_NEM) && defined(IN_RING3)
    104     nemR3NativeNotifyPhysPageChanged(pVM, GCPhys, HCPhysPrev, HCPhysNew, fPageProt, enmType, pu2State);
     103#if defined(VBOX_WITH_NATIVE_NEM)
     104    nemHCNativeNotifyPhysPageChanged(pVM, GCPhys, HCPhysPrev, HCPhysNew, fPageProt, enmType, pu2State);
    105105#else
    106106    RT_NOREF(pVM, GCPhys, HCPhysPrev, HCPhysNew, fPageProt, enmType, pu2State);
  • trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h

    r71136 r71152  
    11/* $Id$ */
    22/** @file
    3  * NEM - Native execution manager, native ring-3 Windows backend.
    4  *
    5  * Log group 2: Exit logging.
    6  * Log group 3: Log context on exit.
    7  * Log group 5: Ring-3 memory management
    8  * Log group 6: Ring-0 memory management
    9  * Log group 12: API intercepts.
     3 * NEM - Native execution manager, Windows code template ring-0/3.
    104 */
    115
     
    2418
    2519/*********************************************************************************************************************************
    26 *   Header Files                                                                                                                 *
    27 *********************************************************************************************************************************/
    28 #define LOG_GROUP LOG_GROUP_NEM
    29 #include <iprt/nt/nt-and-windows.h>
    30 #include <iprt/nt/hyperv.h>
    31 #include <iprt/nt/vid.h>
    32 #include <WinHvPlatform.h>
    33 
    34 #ifndef _WIN32_WINNT_WIN10
    35 # error "Missing _WIN32_WINNT_WIN10"
    36 #endif
    37 #ifndef _WIN32_WINNT_WIN10_RS1 /* Missing define, causing trouble for us. */
    38 # define _WIN32_WINNT_WIN10_RS1 (_WIN32_WINNT_WIN10 + 1)
    39 #endif
    40 #include <sysinfoapi.h>
    41 #include <debugapi.h>
    42 #include <errhandlingapi.h>
    43 #include <fileapi.h>
    44 #include <winerror.h> /* no api header for this. */
    45 
    46 #include <VBox/vmm/nem.h>
    47 #include <VBox/vmm/iem.h>
    48 #include <VBox/vmm/em.h>
    49 #include <VBox/vmm/apic.h>
    50 #include "NEMInternal.h"
    51 #include <VBox/vmm/vm.h>
    52 
    53 #include <iprt/ldr.h>
    54 #include <iprt/path.h>
    55 #include <iprt/string.h>
    56 
    57 
    58 /*********************************************************************************************************************************
    59 *   Defined Constants And Macros                                                                                                 *
    60 *********************************************************************************************************************************/
    61 #ifdef LOG_ENABLED
    62 # define NEM_WIN_INTERCEPT_NT_IO_CTLS
    63 #endif
    64 
    65 /** @name Our two-bit physical page state for PGMPAGE
    66  * @{ */
    67 #define NEM_WIN_PAGE_STATE_NOT_SET      0
    68 #define NEM_WIN_PAGE_STATE_UNMAPPED     1
    69 #define NEM_WIN_PAGE_STATE_READABLE     2
    70 #define NEM_WIN_PAGE_STATE_WRITABLE     3
    71 /** @} */
    72 
    73 /** Checks if a_GCPhys is subject to the limited A20 gate emulation.  */
    74 #define NEM_WIN_IS_SUBJECT_TO_A20(a_GCPhys)     ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K)
    75 
    76 /** Checks if a_GCPhys is relevant to the limited A20 gate emulation.  */
    77 #define NEM_WIN_IS_RELEVANT_TO_A20(a_GCPhys)    \
    78     ( ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K) || ((RTGCPHYS)(a_GCPhys) < (RTGCPHYS)_64K) )
    79 
    80 /** VID I/O control detection: Fake partition handle input. */
    81 #define NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE          ((HANDLE)(uintptr_t)38479125)
    82 /** VID I/O control detection: Fake partition ID return. */
    83 #define NEM_WIN_IOCTL_DETECTOR_FAKE_PARTITION_ID    UINT64_C(0xfa1e000042424242)
    84 /** VID I/O control detection: Fake CPU index input. */
    85 #define NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX        UINT32_C(42)
    86 /** VID I/O control detection: Fake timeout input. */
    87 #define NEM_WIN_IOCTL_DETECTOR_FAKE_TIMEOUT         UINT32_C(0x00080286)
    88 
    89 
    90 /*********************************************************************************************************************************
    9120*   Global Variables                                                                                                             *
    9221*********************************************************************************************************************************/
    93 /** @name APIs imported from WinHvPlatform.dll
    94  * @{ */
    95 static decltype(WHvGetCapability) *                 g_pfnWHvGetCapability;
    96 static decltype(WHvCreatePartition) *               g_pfnWHvCreatePartition;
    97 static decltype(WHvSetupPartition) *                g_pfnWHvSetupPartition;
    98 static decltype(WHvDeletePartition) *               g_pfnWHvDeletePartition;
    99 static decltype(WHvGetPartitionProperty) *          g_pfnWHvGetPartitionProperty;
    100 static decltype(WHvSetPartitionProperty) *          g_pfnWHvSetPartitionProperty;
    101 static decltype(WHvMapGpaRange) *                   g_pfnWHvMapGpaRange;
    102 static decltype(WHvUnmapGpaRange) *                 g_pfnWHvUnmapGpaRange;
    103 static decltype(WHvTranslateGva) *                  g_pfnWHvTranslateGva;
    104 #ifndef NEM_WIN_USE_OUR_OWN_RUN_API
    105 static decltype(WHvCreateVirtualProcessor) *        g_pfnWHvCreateVirtualProcessor;
    106 static decltype(WHvDeleteVirtualProcessor) *        g_pfnWHvDeleteVirtualProcessor;
    107 static decltype(WHvRunVirtualProcessor) *           g_pfnWHvRunVirtualProcessor;
    108 static decltype(WHvGetRunExitContextSize) *         g_pfnWHvGetRunExitContextSize;
    109 static decltype(WHvCancelRunVirtualProcessor) *     g_pfnWHvCancelRunVirtualProcessor;
    110 static decltype(WHvGetVirtualProcessorRegisters) *  g_pfnWHvGetVirtualProcessorRegisters;
    111 static decltype(WHvSetVirtualProcessorRegisters) *  g_pfnWHvSetVirtualProcessorRegisters;
    112 #endif
    113 /** @} */
    114 
    115 /** @name APIs imported from Vid.dll
    116  * @{ */
    117 static decltype(VidGetHvPartitionId)               *g_pfnVidGetHvPartitionId;
    118 static decltype(VidStartVirtualProcessor)          *g_pfnVidStartVirtualProcessor;
    119 static decltype(VidStopVirtualProcessor)           *g_pfnVidStopVirtualProcessor;
    120 static decltype(VidMessageSlotMap)                 *g_pfnVidMessageSlotMap;
    121 static decltype(VidMessageSlotHandleAndGetNext)    *g_pfnVidMessageSlotHandleAndGetNext;
    122 #ifdef LOG_ENABLED
    123 static decltype(VidGetVirtualProcessorState)       *g_pfnVidGetVirtualProcessorState;
    124 static decltype(VidSetVirtualProcessorState)       *g_pfnVidSetVirtualProcessorState;
    125 static decltype(VidGetVirtualProcessorRunningStatus) *g_pfnVidGetVirtualProcessorRunningStatus;
    126 #endif
    127 /** @} */
    128 
    129 
    130 /**
    131  * Import instructions.
    132  */
    133 static const struct
    134 {
    135     uint8_t     idxDll;     /**< 0 for WinHvPlatform.dll, 1 for vid.dll. */
    136     bool        fOptional;  /**< Set if import is optional. */
    137     PFNRT      *ppfn;       /**< The function pointer variable. */
    138     const char *pszName;    /**< The function name. */
    139 } g_aImports[] =
    140 {
    141 #define NEM_WIN_IMPORT(a_idxDll, a_fOptional, a_Name) { (a_idxDll), (a_fOptional), (PFNRT *)&RT_CONCAT(g_pfn,a_Name), #a_Name }
    142     NEM_WIN_IMPORT(0, false, WHvGetCapability),
    143     NEM_WIN_IMPORT(0, false, WHvCreatePartition),
    144     NEM_WIN_IMPORT(0, false, WHvSetupPartition),
    145     NEM_WIN_IMPORT(0, false, WHvDeletePartition),
    146     NEM_WIN_IMPORT(0, false, WHvGetPartitionProperty),
    147     NEM_WIN_IMPORT(0, false, WHvSetPartitionProperty),
    148     NEM_WIN_IMPORT(0, false, WHvMapGpaRange),
    149     NEM_WIN_IMPORT(0, false, WHvUnmapGpaRange),
    150     NEM_WIN_IMPORT(0, false, WHvTranslateGva),
    151 #ifndef NEM_WIN_USE_OUR_OWN_RUN_API
    152     NEM_WIN_IMPORT(0, false, WHvCreateVirtualProcessor),
    153     NEM_WIN_IMPORT(0, false, WHvDeleteVirtualProcessor),
    154     NEM_WIN_IMPORT(0, false, WHvRunVirtualProcessor),
    155     NEM_WIN_IMPORT(0, false, WHvCancelRunVirtualProcessor),
    156     NEM_WIN_IMPORT(0, false, WHvGetRunExitContextSize),
    157     NEM_WIN_IMPORT(0, false, WHvGetVirtualProcessorRegisters),
    158     NEM_WIN_IMPORT(0, false, WHvSetVirtualProcessorRegisters),
    159 #endif
    160     NEM_WIN_IMPORT(1, false, VidGetHvPartitionId),
    161     NEM_WIN_IMPORT(1, false, VidMessageSlotMap),
    162     NEM_WIN_IMPORT(1, false, VidMessageSlotHandleAndGetNext),
    163     NEM_WIN_IMPORT(1, false, VidStartVirtualProcessor),
    164     NEM_WIN_IMPORT(1, false, VidStopVirtualProcessor),
    165 #ifdef LOG_ENABLED
    166     NEM_WIN_IMPORT(1, false, VidGetVirtualProcessorState),
    167     NEM_WIN_IMPORT(1, false, VidSetVirtualProcessorState),
    168     NEM_WIN_IMPORT(1, false, VidGetVirtualProcessorRunningStatus),
    169 #endif
    170 #undef NEM_WIN_IMPORT
    171 };
    172 
    173 
    174 /** The real NtDeviceIoControlFile API in NTDLL.   */
    175 static decltype(NtDeviceIoControlFile) *g_pfnNtDeviceIoControlFile;
    176 /** Pointer to the NtDeviceIoControlFile import table entry. */
    177 static decltype(NtDeviceIoControlFile) **g_ppfnVidNtDeviceIoControlFile;
    178 /** Info about the VidGetHvPartitionId I/O control interface. */
    179 static NEMWINIOCTL g_IoCtlGetHvPartitionId;
    180 /** Info about the VidStartVirtualProcessor I/O control interface. */
    181 static NEMWINIOCTL g_IoCtlStartVirtualProcessor;
    182 /** Info about the VidStopVirtualProcessor I/O control interface. */
    183 static NEMWINIOCTL g_IoCtlStopVirtualProcessor;
    184 /** Info about the VidMessageSlotHandleAndGetNext I/O control interface. */
    185 static NEMWINIOCTL g_IoCtlMessageSlotHandleAndGetNext;
    186 #ifdef LOG_ENABLED
    187 /** Info about the VidMessageSlotMap I/O control interface - for logging. */
    188 static NEMWINIOCTL g_IoCtlMessageSlotMap;
    189 /* Info about the VidGetVirtualProcessorState I/O control interface - for logging. */
    190 static NEMWINIOCTL g_IoCtlGetVirtualProcessorState;
    191 /* Info about the VidSetVirtualProcessorState I/O control interface - for logging. */
    192 static NEMWINIOCTL g_IoCtlSetVirtualProcessorState;
    193 /** Pointer to what nemR3WinIoctlDetector_ForLogging should fill in. */
    194 static NEMWINIOCTL *g_pIoCtlDetectForLogging;
    195 #endif
    196 
    197 #ifdef NEM_WIN_INTERCEPT_NT_IO_CTLS
    198 /** Mapping slot for CPU #0.
    199  * @{  */
    200 static VID_MESSAGE_MAPPING_HEADER            *g_pMsgSlotMapping = NULL;
    201 static const HV_MESSAGE_HEADER               *g_pHvMsgHdr;
    202 static const HV_X64_INTERCEPT_MESSAGE_HEADER *g_pX64MsgHdr;
    203 /** @} */
    204 #endif
    205 
    206 
    207 /*
    208  * Let the preprocessor alias the APIs to import variables for better autocompletion.
    209  */
    210 #ifndef IN_SLICKEDIT
    211 # define WHvGetCapability                           g_pfnWHvGetCapability
    212 # define WHvCreatePartition                         g_pfnWHvCreatePartition
    213 # define WHvSetupPartition                          g_pfnWHvSetupPartition
    214 # define WHvDeletePartition                         g_pfnWHvDeletePartition
    215 # define WHvGetPartitionProperty                    g_pfnWHvGetPartitionProperty
    216 # define WHvSetPartitionProperty                    g_pfnWHvSetPartitionProperty
    217 # define WHvMapGpaRange                             g_pfnWHvMapGpaRange
    218 # define WHvUnmapGpaRange                           g_pfnWHvUnmapGpaRange
    219 # define WHvTranslateGva                            g_pfnWHvTranslateGva
    220 # define WHvCreateVirtualProcessor                  g_pfnWHvCreateVirtualProcessor
    221 # define WHvDeleteVirtualProcessor                  g_pfnWHvDeleteVirtualProcessor
    222 # define WHvRunVirtualProcessor                     g_pfnWHvRunVirtualProcessor
    223 # define WHvGetRunExitContextSize                   g_pfnWHvGetRunExitContextSize
    224 # define WHvCancelRunVirtualProcessor               g_pfnWHvCancelRunVirtualProcessor
    225 # define WHvGetVirtualProcessorRegisters            g_pfnWHvGetVirtualProcessorRegisters
    226 # define WHvSetVirtualProcessorRegisters            g_pfnWHvSetVirtualProcessorRegisters
    227 #endif
    228 
    22922/** NEM_WIN_PAGE_STATE_XXX names. */
    230 static const char * const g_apszPageStates[4] = { "not-set", "unmapped", "readable", "writable" };
    231 /** WHV_MEMORY_ACCESS_TYPE names */
    232 static const char * const g_apszWHvMemAccesstypes[4] = { "read", "write", "exec", "!undefined!" };
     23NEM_TMPL_STATIC const char * const g_apszPageStates[4] = { "not-set", "unmapped", "readable", "writable" };
    23324
    23425
     
    23627*   Internal Functions                                                                                                           *
    23728*********************************************************************************************************************************/
    238 static int nemR3NativeSetPhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst, uint32_t fPageProt,
    239                                   uint8_t *pu2State, bool fBackingChanged);
    240 
    241 
    242 
    243 #ifdef NEM_WIN_INTERCEPT_NT_IO_CTLS
    244 /**
    245  * Wrapper that logs the call from VID.DLL.
    246  *
    247  * This is very handy for figuring out why an API call fails.
    248  */
    249 static NTSTATUS WINAPI
    250 nemR3WinLogWrapper_NtDeviceIoControlFile(HANDLE hFile, HANDLE hEvt, PIO_APC_ROUTINE pfnApcCallback, PVOID pvApcCtx,
    251                                          PIO_STATUS_BLOCK pIos, ULONG uFunction, PVOID pvInput, ULONG cbInput,
    252                                          PVOID pvOutput, ULONG cbOutput)
    253 {
    254 
    255     char szFunction[32];
    256     const char *pszFunction;
    257     if (uFunction == g_IoCtlMessageSlotHandleAndGetNext.uFunction)
    258         pszFunction = "VidMessageSlotHandleAndGetNext";
    259     else if (uFunction == g_IoCtlStartVirtualProcessor.uFunction)
    260         pszFunction = "VidStartVirtualProcessor";
    261     else if (uFunction == g_IoCtlStopVirtualProcessor.uFunction)
    262         pszFunction = "VidStopVirtualProcessor";
    263     else if (uFunction == g_IoCtlMessageSlotMap.uFunction)
    264         pszFunction = "VidMessageSlotMap";
    265     else if (uFunction == g_IoCtlGetVirtualProcessorState.uFunction)
    266         pszFunction = "VidGetVirtualProcessorState";
    267     else if (uFunction == g_IoCtlSetVirtualProcessorState.uFunction)
    268         pszFunction = "VidSetVirtualProcessorState";
    269     else
    270     {
    271         RTStrPrintf(szFunction, sizeof(szFunction), "%#x", uFunction);
    272         pszFunction = szFunction;
    273     }
    274 
    275     if (cbInput > 0 && pvInput)
    276         Log12(("VID!NtDeviceIoControlFile: %s/input: %.*Rhxs\n", pszFunction, RT_MIN(cbInput, 32), pvInput));
    277     NTSTATUS rcNt = g_pfnNtDeviceIoControlFile(hFile, hEvt, pfnApcCallback, pvApcCtx, pIos, uFunction,
    278                                                pvInput, cbInput, pvOutput, cbOutput);
    279     if (!hEvt && !pfnApcCallback && !pvApcCtx)
    280         Log12(("VID!NtDeviceIoControlFile: hFile=%#zx pIos=%p->{s:%#x, i:%#zx} uFunction=%s Input=%p LB %#x Output=%p LB %#x) -> %#x; Caller=%p\n",
    281                hFile, pIos, pIos->Status, pIos->Information, pszFunction, pvInput, cbInput, pvOutput, cbOutput, rcNt, ASMReturnAddress()));
    282     else
    283         Log12(("VID!NtDeviceIoControlFile: hFile=%#zx hEvt=%#zx Apc=%p/%p pIos=%p->{s:%#x, i:%#zx} uFunction=%s Input=%p LB %#x Output=%p LB %#x) -> %#x; Caller=%p\n",
    284                hFile, hEvt, pfnApcCallback, pvApcCtx, pIos, pIos->Status, pIos->Information, pszFunction,
    285                pvInput, cbInput, pvOutput, cbOutput, rcNt, ASMReturnAddress()));
    286     if (cbOutput > 0 && pvOutput)
    287     {
    288         Log12(("VID!NtDeviceIoControlFile: %s/output: %.*Rhxs\n", pszFunction, RT_MIN(cbOutput, 32), pvOutput));
    289         if (uFunction == 0x2210cc && g_pMsgSlotMapping == NULL && cbOutput >= sizeof(void *))
    290         {
    291             g_pMsgSlotMapping = *(VID_MESSAGE_MAPPING_HEADER **)pvOutput;
    292             g_pHvMsgHdr       = (const HV_MESSAGE_HEADER               *)(g_pMsgSlotMapping + 1);
    293             g_pX64MsgHdr      = (const HV_X64_INTERCEPT_MESSAGE_HEADER *)(g_pHvMsgHdr + 1);
    294             Log12(("VID!NtDeviceIoControlFile: Message slot mapping: %p\n", g_pMsgSlotMapping));
    295         }
    296     }
    297     if (   g_pMsgSlotMapping
    298         && (   uFunction == g_IoCtlMessageSlotHandleAndGetNext.uFunction
    299             || uFunction == g_IoCtlStopVirtualProcessor.uFunction
    300             || uFunction == g_IoCtlMessageSlotMap.uFunction
    301                ))
    302         Log12(("VID!NtDeviceIoControlFile: enmVidMsgType=%#x cb=%#x msg=%#x payload=%u cs:rip=%04x:%08RX64 (%s)\n",
    303                g_pMsgSlotMapping->enmVidMsgType, g_pMsgSlotMapping->cbMessage,
    304                g_pHvMsgHdr->MessageType, g_pHvMsgHdr->PayloadSize,
    305                g_pX64MsgHdr->CsSegment.Selector, g_pX64MsgHdr->Rip, pszFunction));
    306 
    307     return rcNt;
    308 }
    309 #endif /* NEM_WIN_INTERCEPT_NT_IO_CTLS */
    310 
    311 
    312 /**
    313  * Patches the call table of VID.DLL so we can intercept NtDeviceIoControlFile.
    314  *
    315  * This is for used to figure out the I/O control codes and in logging builds
    316  * for logging API calls that WinHvPlatform.dll does.
    317  *
    318  * @returns VBox status code.
    319  * @param   hLdrModVid      The VID module handle.
    320  * @param   pErrInfo        Where to return additional error information.
    321  */
    322 static int nemR3WinInitVidIntercepts(RTLDRMOD hLdrModVid, PRTERRINFO pErrInfo)
    323 {
    324     /*
    325      * Locate the real API.
    326      */
    327     g_pfnNtDeviceIoControlFile = (decltype(NtDeviceIoControlFile) *)RTLdrGetSystemSymbol("NTDLL.DLL", "NtDeviceIoControlFile");
    328     AssertReturn(g_pfnNtDeviceIoControlFile != NULL,
    329                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Failed to resolve NtDeviceIoControlFile from NTDLL.DLL"));
    330 
    331     /*
    332      * Locate the PE header and get what we need from it.
    333      */
    334     uint8_t const *pbImage = (uint8_t const *)RTLdrGetNativeHandle(hLdrModVid);
    335     IMAGE_DOS_HEADER const *pMzHdr  = (IMAGE_DOS_HEADER const *)pbImage;
    336     AssertReturn(pMzHdr->e_magic == IMAGE_DOS_SIGNATURE,
    337                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL mapping doesn't start with MZ signature: %#x", pMzHdr->e_magic));
    338     IMAGE_NT_HEADERS const *pNtHdrs = (IMAGE_NT_HEADERS const *)&pbImage[pMzHdr->e_lfanew];
    339     AssertReturn(pNtHdrs->Signature == IMAGE_NT_SIGNATURE,
    340                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL has invalid PE signaturre: %#x @%#x",
    341                                pNtHdrs->Signature, pMzHdr->e_lfanew));
    342 
    343     uint32_t const             cbImage   = pNtHdrs->OptionalHeader.SizeOfImage;
    344     IMAGE_DATA_DIRECTORY const ImportDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    345 
    346     /*
    347      * Walk the import descriptor table looking for NTDLL.DLL.
    348      */
    349     AssertReturn(   ImportDir.Size > 0
    350                  && ImportDir.Size < cbImage,
    351                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL bad import directory size: %#x", ImportDir.Size));
    352     AssertReturn(   ImportDir.VirtualAddress > 0
    353                  && ImportDir.VirtualAddress <= cbImage - ImportDir.Size,
    354                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL bad import directory RVA: %#x", ImportDir.VirtualAddress));
    355 
    356     for (PIMAGE_IMPORT_DESCRIPTOR pImps = (PIMAGE_IMPORT_DESCRIPTOR)&pbImage[ImportDir.VirtualAddress];
    357          pImps->Name != 0 && pImps->FirstThunk != 0;
    358          pImps++)
    359     {
    360         AssertReturn(pImps->Name < cbImage,
    361                      RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL bad import directory entry name: %#x", pImps->Name));
    362         const char *pszModName = (const char *)&pbImage[pImps->Name];
    363         if (RTStrICmpAscii(pszModName, "ntdll.dll"))
    364             continue;
    365         AssertReturn(pImps->FirstThunk < cbImage,
    366                      RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL bad FirstThunk: %#x", pImps->FirstThunk));
    367         AssertReturn(pImps->OriginalFirstThunk < cbImage,
    368                      RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL bad FirstThunk: %#x", pImps->FirstThunk));
    369 
    370         /*
    371          * Walk the thunks table(s) looking for NtDeviceIoControlFile.
    372          */
    373         PIMAGE_THUNK_DATA pFirstThunk = (PIMAGE_THUNK_DATA)&pbImage[pImps->FirstThunk]; /* update this. */
    374         PIMAGE_THUNK_DATA pThunk      = pImps->OriginalFirstThunk == 0                  /* read from this. */
    375                                       ? (PIMAGE_THUNK_DATA)&pbImage[pImps->FirstThunk]
    376                                       : (PIMAGE_THUNK_DATA)&pbImage[pImps->OriginalFirstThunk];
    377         while (pThunk->u1.Ordinal != 0)
    378         {
    379             if (!(pThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG32))
    380             {
    381                 AssertReturn(pThunk->u1.Ordinal > 0 && pThunk->u1.Ordinal < cbImage,
    382                              RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "VID.DLL bad FirstThunk: %#x", pImps->FirstThunk));
    383 
    384                 const char *pszSymbol = (const char *)&pbImage[(uintptr_t)pThunk->u1.AddressOfData + 2];
    385                 if (strcmp(pszSymbol, "NtDeviceIoControlFile") == 0)
    386                 {
    387                     DWORD fOldProt = PAGE_READONLY;
    388                     VirtualProtect(&pFirstThunk->u1.Function, sizeof(uintptr_t), PAGE_EXECUTE_READWRITE, &fOldProt);
    389                     g_ppfnVidNtDeviceIoControlFile = (decltype(NtDeviceIoControlFile) **)&pFirstThunk->u1.Function;
    390                     /* Don't restore the protection here, so we modify the NtDeviceIoControlFile pointer later. */
    391                 }
    392             }
    393 
    394             pThunk++;
    395             pFirstThunk++;
    396         }
    397     }
    398 
    399     if (*g_ppfnVidNtDeviceIoControlFile)
    400     {
    401 #ifdef NEM_WIN_INTERCEPT_NT_IO_CTLS
    402         *g_ppfnVidNtDeviceIoControlFile = nemR3WinLogWrapper_NtDeviceIoControlFile;
    403 #endif
    404         return VINF_SUCCESS;
    405     }
    406     return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Failed to patch NtDeviceIoControlFile import in VID.DLL!");
    407 }
    408 
    409 
    410 /**
    411  * Worker for nemR3NativeInit that probes and load the native API.
    412  *
    413  * @returns VBox status code.
    414  * @param   fForced             Whether the HMForced flag is set and we should
    415  *                              fail if we cannot initialize.
    416  * @param   pErrInfo            Where to always return error info.
    417  */
    418 static int nemR3WinInitProbeAndLoad(bool fForced, PRTERRINFO pErrInfo)
    419 {
    420     /*
    421      * Check that the DLL files we need are present, but without loading them.
    422      * We'd like to avoid loading them unnecessarily.
    423      */
    424     WCHAR wszPath[MAX_PATH + 64];
    425     UINT  cwcPath = GetSystemDirectoryW(wszPath, MAX_PATH);
    426     if (cwcPath >= MAX_PATH || cwcPath < 2)
    427         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "GetSystemDirectoryW failed (%#x / %u)", cwcPath, GetLastError());
    428 
    429     if (wszPath[cwcPath - 1] != '\\' || wszPath[cwcPath - 1] != '/')
    430         wszPath[cwcPath++] = '\\';
    431     RTUtf16CopyAscii(&wszPath[cwcPath], RT_ELEMENTS(wszPath) - cwcPath, "WinHvPlatform.dll");
    432     if (GetFileAttributesW(wszPath) == INVALID_FILE_ATTRIBUTES)
    433         return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "The native API dll was not found (%ls)", wszPath);
    434 
    435     /*
    436      * Check that we're in a VM and that the hypervisor identifies itself as Hyper-V.
    437      */
    438     if (!ASMHasCpuId())
    439         return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID support");
    440     if (!ASMIsValidStdRange(ASMCpuId_EAX(0)))
    441         return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID leaf #1");
    442     if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
    443         return RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Not in a hypervisor partition (HVP=0)");
    444 
    445     uint32_t cMaxHyperLeaf = 0;
    446     uint32_t uEbx = 0;
    447     uint32_t uEcx = 0;
    448     uint32_t uEdx = 0;
    449     ASMCpuIdExSlow(0x40000000, 0, 0, 0, &cMaxHyperLeaf, &uEbx, &uEcx, &uEdx);
    450     if (!ASMIsValidHypervisorRange(cMaxHyperLeaf))
    451         return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Invalid hypervisor CPUID range (%#x %#x %#x %#x)",
    452                              cMaxHyperLeaf, uEbx, uEcx, uEdx);
    453     if (   uEbx != UINT32_C(0x7263694d) /* Micr */
    454         || uEcx != UINT32_C(0x666f736f) /* osof */
    455         || uEdx != UINT32_C(0x76482074) /* t Hv */)
    456         return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
    457                              "Not Hyper-V CPUID signature: %#x %#x %#x (expected %#x %#x %#x)",
    458                              uEbx, uEcx, uEdx, UINT32_C(0x7263694d), UINT32_C(0x666f736f), UINT32_C(0x76482074));
    459     if (cMaxHyperLeaf < UINT32_C(0x40000005))
    460         return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Too narrow hypervisor CPUID range (%#x)", cMaxHyperLeaf);
    461 
    462     /** @todo would be great if we could recognize a root partition from the
    463      *        CPUID info, but I currently don't dare do that. */
    464 
    465     /*
    466      * Now try load the DLLs and resolve the APIs.
    467      */
    468     static const char * const s_apszDllNames[2] = { "WinHvPlatform.dll",  "vid.dll" };
    469     RTLDRMOD                  ahMods[2]         = { NIL_RTLDRMOD,          NIL_RTLDRMOD };
    470     int                       rc = VINF_SUCCESS;
    471     for (unsigned i = 0; i < RT_ELEMENTS(s_apszDllNames); i++)
    472     {
    473         int rc2 = RTLdrLoadSystem(s_apszDllNames[i], true /*fNoUnload*/, &ahMods[i]);
    474         if (RT_FAILURE(rc2))
    475         {
    476             if (!RTErrInfoIsSet(pErrInfo))
    477                 RTErrInfoSetF(pErrInfo, rc2, "Failed to load API DLL: %s: %Rrc", s_apszDllNames[i], rc2);
    478             else
    479                 RTErrInfoAddF(pErrInfo, rc2, "; %s: %Rrc", s_apszDllNames[i], rc2);
    480             ahMods[i] = NIL_RTLDRMOD;
    481             rc = VERR_NEM_INIT_FAILED;
    482         }
    483     }
    484     if (RT_SUCCESS(rc))
    485         rc = nemR3WinInitVidIntercepts(ahMods[1], pErrInfo);
    486     if (RT_SUCCESS(rc))
    487     {
    488         for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++)
    489         {
    490             int rc2 = RTLdrGetSymbol(ahMods[g_aImports[i].idxDll], g_aImports[i].pszName, (void **)g_aImports[i].ppfn);
    491             if (RT_FAILURE(rc2))
    492             {
    493                 *g_aImports[i].ppfn = NULL;
    494 
    495                 LogRel(("NEM:  %s: Failed to import %s!%s: %Rrc",
    496                         g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error",
    497                         s_apszDllNames[g_aImports[i].idxDll], g_aImports[i].pszName, rc2));
    498                 if (!g_aImports[i].fOptional)
    499                 {
    500                     if (RTErrInfoIsSet(pErrInfo))
    501                         RTErrInfoAddF(pErrInfo, rc2, ", %s!%s",
    502                                       s_apszDllNames[g_aImports[i].idxDll], g_aImports[i].pszName);
    503                     else
    504                         rc = RTErrInfoSetF(pErrInfo, rc2, "Failed to import: %s!%s",
    505                                            s_apszDllNames[g_aImports[i].idxDll], g_aImports[i].pszName);
    506                     Assert(RT_FAILURE(rc));
    507                 }
    508             }
    509         }
    510         if (RT_SUCCESS(rc))
    511         {
    512             Assert(!RTErrInfoIsSet(pErrInfo));
    513         }
    514     }
    515 
    516     for (unsigned i = 0; i < RT_ELEMENTS(ahMods); i++)
    517         RTLdrClose(ahMods[i]);
    518     return rc;
    519 }
    520 
    521 
    522 /**
    523  * Worker for nemR3NativeInit that gets the hypervisor capabilities.
    524  *
    525  * @returns VBox status code.
    526  * @param   pVM                 The cross context VM structure.
    527  * @param   pErrInfo            Where to always return error info.
    528  */
    529 static int nemR3WinInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo)
    530 {
    531 #define NEM_LOG_REL_CAP_EX(a_szField, a_szFmt, a_Value)     LogRel(("NEM: %-38s= " a_szFmt "\n", a_szField, a_Value))
    532 #define NEM_LOG_REL_CAP_SUB_EX(a_szField, a_szFmt, a_Value) LogRel(("NEM:   %36s: " a_szFmt "\n", a_szField, a_Value))
    533 #define NEM_LOG_REL_CAP_SUB(a_szField, a_Value)             NEM_LOG_REL_CAP_SUB_EX(a_szField, "%d", a_Value)
    534 
    535     /*
    536      * Is the hypervisor present with the desired capability?
    537      *
    538      * In build 17083 this translates into:
    539      *      - CPUID[0x00000001].HVP is set
    540      *      - CPUID[0x40000000] == "Microsoft Hv"
    541      *      - CPUID[0x40000001].eax == "Hv#1"
    542      *      - CPUID[0x40000003].ebx[12] is set.
    543      *      - VidGetExoPartitionProperty(INVALID_HANDLE_VALUE, 0x60000, &Ignored) returns
    544      *        a non-zero value.
    545      */
    546     /**
    547      * @todo Someone at Microsoft please explain weird API design:
    548      *   1. Pointless CapabilityCode duplication int the output;
    549      *   2. No output size.
    550      */
    551     WHV_CAPABILITY Caps;
    552     RT_ZERO(Caps);
    553     SetLastError(0);
    554     HRESULT hrc = WHvGetCapability(WHvCapabilityCodeHypervisorPresent, &Caps, sizeof(Caps));
    555     DWORD   rcWin = GetLastError();
    556     if (FAILED(hrc))
    557         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    558                              "WHvGetCapability/WHvCapabilityCodeHypervisorPresent failed: %Rhrc (Last=%#x/%u)",
    559                              hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    560     if (!Caps.HypervisorPresent)
    561     {
    562         if (!RTPathExists(RTPATH_NT_PASSTHRU_PREFIX "Device\\VidExo"))
    563             return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE,
    564                                  "WHvCapabilityCodeHypervisorPresent is FALSE! Make sure you have enabled the 'Windows Hypervisor Platform' feature.");
    565         return RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "WHvCapabilityCodeHypervisorPresent is FALSE! (%u)", rcWin);
    566     }
    567     LogRel(("NEM: WHvCapabilityCodeHypervisorPresent is TRUE, so this might work...\n"));
    568 
    569 
    570     /*
    571      * Check what extended VM exits are supported.
    572      */
    573     RT_ZERO(Caps);
    574     hrc = WHvGetCapability(WHvCapabilityCodeExtendedVmExits, &Caps, sizeof(Caps));
    575     if (FAILED(hrc))
    576         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    577                              "WHvGetCapability/WHvCapabilityCodeExtendedVmExits failed: %Rhrc (Last=%#x/%u)",
    578                              hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    579     NEM_LOG_REL_CAP_EX("WHvCapabilityCodeExtendedVmExits", "%'#018RX64", Caps.ExtendedVmExits.AsUINT64);
    580     pVM->nem.s.fExtendedMsrExit   = RT_BOOL(Caps.ExtendedVmExits.X64MsrExit);
    581     pVM->nem.s.fExtendedCpuIdExit = RT_BOOL(Caps.ExtendedVmExits.X64CpuidExit);
    582     pVM->nem.s.fExtendedXcptExit  = RT_BOOL(Caps.ExtendedVmExits.ExceptionExit);
    583     NEM_LOG_REL_CAP_SUB("fExtendedMsrExit",   pVM->nem.s.fExtendedMsrExit);
    584     NEM_LOG_REL_CAP_SUB("fExtendedCpuIdExit", pVM->nem.s.fExtendedCpuIdExit);
    585     NEM_LOG_REL_CAP_SUB("fExtendedXcptExit",  pVM->nem.s.fExtendedXcptExit);
    586     if (Caps.ExtendedVmExits.AsUINT64 & ~(uint64_t)7)
    587         LogRel(("NEM: Warning! Unknown VM exit definitions: %#RX64\n", Caps.ExtendedVmExits.AsUINT64));
    588     /** @todo RECHECK: WHV_EXTENDED_VM_EXITS typedef. */
    589 
    590     /*
    591      * Check features in case they end up defining any.
    592      */
    593     RT_ZERO(Caps);
    594     hrc = WHvGetCapability(WHvCapabilityCodeFeatures, &Caps, sizeof(Caps));
    595     if (FAILED(hrc))
    596         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    597                              "WHvGetCapability/WHvCapabilityCodeFeatures failed: %Rhrc (Last=%#x/%u)",
    598                              hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    599     if (Caps.Features.AsUINT64 & ~(uint64_t)0)
    600         LogRel(("NEM: Warning! Unknown feature definitions: %#RX64\n", Caps.Features.AsUINT64));
    601     /** @todo RECHECK: WHV_CAPABILITY_FEATURES typedef. */
    602 
    603     /*
    604      * Check that the CPU vendor is supported.
    605      */
    606     RT_ZERO(Caps);
    607     hrc = WHvGetCapability(WHvCapabilityCodeProcessorVendor, &Caps, sizeof(Caps));
    608     if (FAILED(hrc))
    609         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    610                              "WHvGetCapability/WHvCapabilityCodeProcessorVendor failed: %Rhrc (Last=%#x/%u)",
    611                              hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    612     switch (Caps.ProcessorVendor)
    613     {
    614         /** @todo RECHECK: WHV_PROCESSOR_VENDOR typedef. */
    615         case WHvProcessorVendorIntel:
    616             NEM_LOG_REL_CAP_EX("WHvCapabilityCodeProcessorVendor", "%d - Intel", Caps.ProcessorVendor);
    617             pVM->nem.s.enmCpuVendor = CPUMCPUVENDOR_INTEL;
    618             break;
    619         case WHvProcessorVendorAmd:
    620             NEM_LOG_REL_CAP_EX("WHvCapabilityCodeProcessorVendor", "%d - AMD", Caps.ProcessorVendor);
    621             pVM->nem.s.enmCpuVendor = CPUMCPUVENDOR_AMD;
    622             break;
    623         default:
    624             NEM_LOG_REL_CAP_EX("WHvCapabilityCodeProcessorVendor", "%d", Caps.ProcessorVendor);
    625             return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Unknown processor vendor: %d", Caps.ProcessorVendor);
    626     }
    627 
    628     /*
    629      * CPU features, guessing these are virtual CPU features?
    630      */
    631     RT_ZERO(Caps);
    632     hrc = WHvGetCapability(WHvCapabilityCodeProcessorFeatures, &Caps, sizeof(Caps));
    633     if (FAILED(hrc))
    634         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    635                              "WHvGetCapability/WHvCapabilityCodeProcessorFeatures failed: %Rhrc (Last=%#x/%u)",
    636                              hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    637     NEM_LOG_REL_CAP_EX("WHvCapabilityCodeProcessorFeatures", "%'#018RX64", Caps.ProcessorFeatures.AsUINT64);
    638 #define NEM_LOG_REL_CPU_FEATURE(a_Field)    NEM_LOG_REL_CAP_SUB(#a_Field, Caps.ProcessorFeatures.a_Field)
    639     NEM_LOG_REL_CPU_FEATURE(Sse3Support);
    640     NEM_LOG_REL_CPU_FEATURE(LahfSahfSupport);
    641     NEM_LOG_REL_CPU_FEATURE(Ssse3Support);
    642     NEM_LOG_REL_CPU_FEATURE(Sse4_1Support);
    643     NEM_LOG_REL_CPU_FEATURE(Sse4_2Support);
    644     NEM_LOG_REL_CPU_FEATURE(Sse4aSupport);
    645     NEM_LOG_REL_CPU_FEATURE(XopSupport);
    646     NEM_LOG_REL_CPU_FEATURE(PopCntSupport);
    647     NEM_LOG_REL_CPU_FEATURE(Cmpxchg16bSupport);
    648     NEM_LOG_REL_CPU_FEATURE(Altmovcr8Support);
    649     NEM_LOG_REL_CPU_FEATURE(LzcntSupport);
    650     NEM_LOG_REL_CPU_FEATURE(MisAlignSseSupport);
    651     NEM_LOG_REL_CPU_FEATURE(MmxExtSupport);
    652     NEM_LOG_REL_CPU_FEATURE(Amd3DNowSupport);
    653     NEM_LOG_REL_CPU_FEATURE(ExtendedAmd3DNowSupport);
    654     NEM_LOG_REL_CPU_FEATURE(Page1GbSupport);
    655     NEM_LOG_REL_CPU_FEATURE(AesSupport);
    656     NEM_LOG_REL_CPU_FEATURE(PclmulqdqSupport);
    657     NEM_LOG_REL_CPU_FEATURE(PcidSupport);
    658     NEM_LOG_REL_CPU_FEATURE(Fma4Support);
    659     NEM_LOG_REL_CPU_FEATURE(F16CSupport);
    660     NEM_LOG_REL_CPU_FEATURE(RdRandSupport);
    661     NEM_LOG_REL_CPU_FEATURE(RdWrFsGsSupport);
    662     NEM_LOG_REL_CPU_FEATURE(SmepSupport);
    663     NEM_LOG_REL_CPU_FEATURE(EnhancedFastStringSupport);
    664     NEM_LOG_REL_CPU_FEATURE(Bmi1Support);
    665     NEM_LOG_REL_CPU_FEATURE(Bmi2Support);
    666     /* two reserved bits here, see below */
    667     NEM_LOG_REL_CPU_FEATURE(MovbeSupport);
    668     NEM_LOG_REL_CPU_FEATURE(Npiep1Support);
    669     NEM_LOG_REL_CPU_FEATURE(DepX87FPUSaveSupport);
    670     NEM_LOG_REL_CPU_FEATURE(RdSeedSupport);
    671     NEM_LOG_REL_CPU_FEATURE(AdxSupport);
    672     NEM_LOG_REL_CPU_FEATURE(IntelPrefetchSupport);
    673     NEM_LOG_REL_CPU_FEATURE(SmapSupport);
    674     NEM_LOG_REL_CPU_FEATURE(HleSupport);
    675     NEM_LOG_REL_CPU_FEATURE(RtmSupport);
    676     NEM_LOG_REL_CPU_FEATURE(RdtscpSupport);
    677     NEM_LOG_REL_CPU_FEATURE(ClflushoptSupport);
    678     NEM_LOG_REL_CPU_FEATURE(ClwbSupport);
    679     NEM_LOG_REL_CPU_FEATURE(ShaSupport);
    680     NEM_LOG_REL_CPU_FEATURE(X87PointersSavedSupport);
    681 #undef NEM_LOG_REL_CPU_FEATURE
    682     if (Caps.ProcessorFeatures.AsUINT64 & (~(RT_BIT_64(43) - 1) | RT_BIT_64(27) | RT_BIT_64(28)))
    683         LogRel(("NEM: Warning! Unknown CPU features: %#RX64\n", Caps.ProcessorFeatures.AsUINT64));
    684     pVM->nem.s.uCpuFeatures.u64 = Caps.ProcessorFeatures.AsUINT64;
    685     /** @todo RECHECK: WHV_PROCESSOR_FEATURES typedef. */
    686 
    687     /*
    688      * The cache line flush size.
    689      */
    690     RT_ZERO(Caps);
    691     hrc = WHvGetCapability(WHvCapabilityCodeProcessorClFlushSize, &Caps, sizeof(Caps));
    692     if (FAILED(hrc))
    693         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    694                              "WHvGetCapability/WHvCapabilityCodeProcessorClFlushSize failed: %Rhrc (Last=%#x/%u)",
    695                              hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    696     NEM_LOG_REL_CAP_EX("WHvCapabilityCodeProcessorClFlushSize", "2^%u", Caps.ProcessorClFlushSize);
    697     if (Caps.ProcessorClFlushSize < 8 && Caps.ProcessorClFlushSize > 9)
    698         return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Unsupported cache line flush size: %u", Caps.ProcessorClFlushSize);
    699     pVM->nem.s.cCacheLineFlushShift = Caps.ProcessorClFlushSize;
    700 
    701     /*
    702      * See if they've added more properties that we're not aware of.
    703      */
    704     /** @todo RECHECK: WHV_CAPABILITY_CODE typedef. */
    705     if (!IsDebuggerPresent()) /* Too noisy when in debugger, so skip. */
    706     {
    707         static const struct
    708         {
    709             uint32_t iMin, iMax; } s_aUnknowns[] =
    710         {
    711             { 0x0003, 0x000f },
    712             { 0x1003, 0x100f },
    713             { 0x2000, 0x200f },
    714             { 0x3000, 0x300f },
    715             { 0x4000, 0x400f },
    716         };
    717         for (uint32_t j = 0; j < RT_ELEMENTS(s_aUnknowns); j++)
    718             for (uint32_t i = s_aUnknowns[j].iMin; i <= s_aUnknowns[j].iMax; i++)
    719             {
    720                 RT_ZERO(Caps);
    721                 hrc = WHvGetCapability((WHV_CAPABILITY_CODE)i, &Caps, sizeof(Caps));
    722                 if (SUCCEEDED(hrc))
    723                     LogRel(("NEM: Warning! Unknown capability %#x returning: %.*Rhxs\n", i, sizeof(Caps), &Caps));
    724             }
    725     }
    726 
    727 #undef NEM_LOG_REL_CAP_EX
    728 #undef NEM_LOG_REL_CAP_SUB_EX
    729 #undef NEM_LOG_REL_CAP_SUB
    730     return VINF_SUCCESS;
    731 }
    732 
    733 
    734 /**
    735  * Used to fill in g_IoCtlGetHvPartitionId.
    736  */
    737 static NTSTATUS WINAPI
    738 nemR3WinIoctlDetector_GetHvPartitionId(HANDLE hFile, HANDLE hEvt, PIO_APC_ROUTINE pfnApcCallback, PVOID pvApcCtx,
    739                                        PIO_STATUS_BLOCK pIos, ULONG uFunction, PVOID pvInput, ULONG cbInput,
    740                                        PVOID pvOutput, ULONG cbOutput)
    741 {
    742     AssertLogRelMsgReturn(hFile == NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, ("hFile=%p\n", hFile), STATUS_INVALID_PARAMETER_1);
    743     RT_NOREF(hEvt); RT_NOREF(pfnApcCallback); RT_NOREF(pvApcCtx);
    744     AssertLogRelMsgReturn(RT_VALID_PTR(pIos), ("pIos=%p\n", pIos), STATUS_INVALID_PARAMETER_5);
    745     AssertLogRelMsgReturn(cbInput == 0, ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_8);
    746     RT_NOREF(pvInput);
    747 
    748     AssertLogRelMsgReturn(RT_VALID_PTR(pvOutput), ("pvOutput=%p\n", pvOutput), STATUS_INVALID_PARAMETER_9);
    749     AssertLogRelMsgReturn(cbOutput == sizeof(HV_PARTITION_ID), ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_10);
    750     *(HV_PARTITION_ID *)pvOutput = NEM_WIN_IOCTL_DETECTOR_FAKE_PARTITION_ID;
    751 
    752     g_IoCtlGetHvPartitionId.cbInput   = cbInput;
    753     g_IoCtlGetHvPartitionId.cbOutput  = cbOutput;
    754     g_IoCtlGetHvPartitionId.uFunction = uFunction;
    755 
    756     return STATUS_SUCCESS;
    757 }
    758 
    759 
    760 /**
    761  * Used to fill in g_IoCtlStartVirtualProcessor.
    762  */
    763 static NTSTATUS WINAPI
    764 nemR3WinIoctlDetector_StartVirtualProcessor(HANDLE hFile, HANDLE hEvt, PIO_APC_ROUTINE pfnApcCallback, PVOID pvApcCtx,
    765                                             PIO_STATUS_BLOCK pIos, ULONG uFunction, PVOID pvInput, ULONG cbInput,
    766                                             PVOID pvOutput, ULONG cbOutput)
    767 {
    768     AssertLogRelMsgReturn(hFile == NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, ("hFile=%p\n", hFile), STATUS_INVALID_PARAMETER_1);
    769     RT_NOREF(hEvt); RT_NOREF(pfnApcCallback); RT_NOREF(pvApcCtx);
    770     AssertLogRelMsgReturn(RT_VALID_PTR(pIos), ("pIos=%p\n", pIos), STATUS_INVALID_PARAMETER_5);
    771     AssertLogRelMsgReturn(cbInput == sizeof(HV_VP_INDEX), ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_8);
    772     AssertLogRelMsgReturn(RT_VALID_PTR(pvInput), ("pvInput=%p\n", pvInput), STATUS_INVALID_PARAMETER_9);
    773     AssertLogRelMsgReturn(*(HV_VP_INDEX *)pvInput == NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX,
    774                           ("*piCpu=%u\n", *(HV_VP_INDEX *)pvInput), STATUS_INVALID_PARAMETER_9);
    775     AssertLogRelMsgReturn(cbOutput == 0, ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_10);
    776     RT_NOREF(pvOutput);
    777 
    778     g_IoCtlStartVirtualProcessor.cbInput   = cbInput;
    779     g_IoCtlStartVirtualProcessor.cbOutput  = cbOutput;
    780     g_IoCtlStartVirtualProcessor.uFunction = uFunction;
    781 
    782     return STATUS_SUCCESS;
    783 }
    784 
    785 
    786 /**
    787  * Used to fill in g_IoCtlStartVirtualProcessor.
    788  */
    789 static NTSTATUS WINAPI
    790 nemR3WinIoctlDetector_StopVirtualProcessor(HANDLE hFile, HANDLE hEvt, PIO_APC_ROUTINE pfnApcCallback, PVOID pvApcCtx,
    791                                            PIO_STATUS_BLOCK pIos, ULONG uFunction, PVOID pvInput, ULONG cbInput,
    792                                            PVOID pvOutput, ULONG cbOutput)
    793 {
    794     AssertLogRelMsgReturn(hFile == NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, ("hFile=%p\n", hFile), STATUS_INVALID_PARAMETER_1);
    795     RT_NOREF(hEvt); RT_NOREF(pfnApcCallback); RT_NOREF(pvApcCtx);
    796     AssertLogRelMsgReturn(RT_VALID_PTR(pIos), ("pIos=%p\n", pIos), STATUS_INVALID_PARAMETER_5);
    797     AssertLogRelMsgReturn(cbInput == sizeof(HV_VP_INDEX), ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_8);
    798     AssertLogRelMsgReturn(RT_VALID_PTR(pvInput), ("pvInput=%p\n", pvInput), STATUS_INVALID_PARAMETER_9);
    799     AssertLogRelMsgReturn(*(HV_VP_INDEX *)pvInput == NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX,
    800                           ("*piCpu=%u\n", *(HV_VP_INDEX *)pvInput), STATUS_INVALID_PARAMETER_9);
    801     AssertLogRelMsgReturn(cbOutput == 0, ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_10);
    802     RT_NOREF(pvOutput);
    803 
    804     g_IoCtlStopVirtualProcessor.cbInput   = cbInput;
    805     g_IoCtlStopVirtualProcessor.cbOutput  = cbOutput;
    806     g_IoCtlStopVirtualProcessor.uFunction = uFunction;
    807 
    808     return STATUS_SUCCESS;
    809 }
    810 
    811 
    812 /**
    813  * Used to fill in g_IoCtlMessageSlotHandleAndGetNext
    814  */
    815 static NTSTATUS WINAPI
    816 nemR3WinIoctlDetector_MessageSlotHandleAndGetNext(HANDLE hFile, HANDLE hEvt, PIO_APC_ROUTINE pfnApcCallback, PVOID pvApcCtx,
    817                                                   PIO_STATUS_BLOCK pIos, ULONG uFunction, PVOID pvInput, ULONG cbInput,
    818                                                   PVOID pvOutput, ULONG cbOutput)
    819 {
    820     AssertLogRelMsgReturn(hFile == NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, ("hFile=%p\n", hFile), STATUS_INVALID_PARAMETER_1);
    821     RT_NOREF(hEvt); RT_NOREF(pfnApcCallback); RT_NOREF(pvApcCtx);
    822     AssertLogRelMsgReturn(RT_VALID_PTR(pIos), ("pIos=%p\n", pIos), STATUS_INVALID_PARAMETER_5);
    823 
    824     AssertLogRelMsgReturn(cbInput == sizeof(VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT), ("cbInput=%#x\n", cbInput),
    825                           STATUS_INVALID_PARAMETER_8);
    826     AssertLogRelMsgReturn(RT_VALID_PTR(pvInput), ("pvInput=%p\n", pvInput), STATUS_INVALID_PARAMETER_9);
    827     PCVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT pVidIn = (PCVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT)pvInput;
    828     AssertLogRelMsgReturn(   pVidIn->iCpu == NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX
    829                           && pVidIn->fFlags == VID_MSHAGN_F_HANDLE_MESSAGE
    830                           && pVidIn->cMillies == NEM_WIN_IOCTL_DETECTOR_FAKE_TIMEOUT,
    831                           ("iCpu=%u fFlags=%#x cMillies=%#x\n", pVidIn->iCpu, pVidIn->fFlags, pVidIn->cMillies),
    832                           STATUS_INVALID_PARAMETER_9);
    833     AssertLogRelMsgReturn(cbOutput == 0, ("cbInput=%#x\n", cbInput), STATUS_INVALID_PARAMETER_10);
    834     RT_NOREF(pvOutput);
    835 
    836     g_IoCtlMessageSlotHandleAndGetNext.cbInput   = cbInput;
    837     g_IoCtlMessageSlotHandleAndGetNext.cbOutput  = cbOutput;
    838     g_IoCtlMessageSlotHandleAndGetNext.uFunction = uFunction;
    839 
    840     return STATUS_SUCCESS;
    841 }
    842 
    843 
    844 #ifdef LOG_ENABLED
    845 /**
    846  * Used to fill in what g_pIoCtlDetectForLogging points to.
    847  */
    848 static NTSTATUS WINAPI nemR3WinIoctlDetector_ForLogging(HANDLE hFile, HANDLE hEvt, PIO_APC_ROUTINE pfnApcCallback, PVOID pvApcCtx,
    849                                                         PIO_STATUS_BLOCK pIos, ULONG uFunction, PVOID pvInput, ULONG cbInput,
    850                                                         PVOID pvOutput, ULONG cbOutput)
    851 {
    852     RT_NOREF(hFile, hEvt, pfnApcCallback, pvApcCtx, pIos, pvInput, pvOutput);
    853 
    854     g_pIoCtlDetectForLogging->cbInput   = cbInput;
    855     g_pIoCtlDetectForLogging->cbOutput  = cbOutput;
    856     g_pIoCtlDetectForLogging->uFunction = uFunction;
    857 
    858     return STATUS_SUCCESS;
    859 }
    860 #endif
    861 
    862 
    863 /**
    864  * Worker for nemR3NativeInit that detect I/O control function numbers for VID.
    865  *
    866  * We use the function numbers directly in ring-0 and to name functions when
    867  * logging NtDeviceIoControlFile calls.
    868  *
    869  * @note    We could alternatively do this by disassembling the respective
    870  *          functions, but hooking NtDeviceIoControlFile and making fake calls
    871  *          more easily provides the desired information.
    872  *
    873  * @returns VBox status code.
    874  * @param   pVM                 The cross context VM structure.  Will set I/O
    875  *                              control info members.
    876  * @param   pErrInfo            Where to always return error info.
    877  */
    878 static int nemR3WinInitDiscoverIoControlProperties(PVM pVM, PRTERRINFO pErrInfo)
    879 {
    880     /*
    881      * Probe the I/O control information for select VID APIs so we can use
    882      * them directly from ring-0 and better log them.
    883      *
    884      */
    885     decltype(NtDeviceIoControlFile) * const pfnOrg = *g_ppfnVidNtDeviceIoControlFile;
    886 
    887     /* VidGetHvPartitionId */
    888     *g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_GetHvPartitionId;
    889     HV_PARTITION_ID idHvPartition = HV_PARTITION_ID_INVALID;
    890     BOOL fRet = g_pfnVidGetHvPartitionId(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, &idHvPartition);
    891     *g_ppfnVidNtDeviceIoControlFile = pfnOrg;
    892     AssertReturn(fRet && idHvPartition == NEM_WIN_IOCTL_DETECTOR_FAKE_PARTITION_ID && g_IoCtlGetHvPartitionId.uFunction != 0,
    893                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    894                                "Problem figuring out VidGetHvPartitionId: fRet=%u idHvPartition=%#x dwErr=%u",
    895                                fRet, idHvPartition, GetLastError()) );
    896     LogRel(("NEM: VidGetHvPartitionId            -> fun:%#x in:%#x out:%#x\n",
    897             g_IoCtlGetHvPartitionId.uFunction, g_IoCtlGetHvPartitionId.cbInput, g_IoCtlGetHvPartitionId.cbOutput));
    898 
    899     /* VidStartVirtualProcessor */
    900     *g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_StartVirtualProcessor;
    901     fRet = g_pfnVidStartVirtualProcessor(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX);
    902     *g_ppfnVidNtDeviceIoControlFile = pfnOrg;
    903     AssertReturn(fRet && g_IoCtlStartVirtualProcessor.uFunction != 0,
    904                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    905                                "Problem figuring out VidStartVirtualProcessor: fRet=%u dwErr=%u",
    906                                fRet, GetLastError()) );
    907     LogRel(("NEM: VidStartVirtualProcessor       -> fun:%#x in:%#x out:%#x\n", g_IoCtlStartVirtualProcessor.uFunction,
    908             g_IoCtlStartVirtualProcessor.cbInput, g_IoCtlStartVirtualProcessor.cbOutput));
    909 
    910     /* VidStopVirtualProcessor */
    911     *g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_StopVirtualProcessor;
    912     fRet = g_pfnVidStopVirtualProcessor(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX);
    913     *g_ppfnVidNtDeviceIoControlFile = pfnOrg;
    914     AssertReturn(fRet && g_IoCtlStopVirtualProcessor.uFunction != 0,
    915                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    916                                "Problem figuring out VidStopVirtualProcessor: fRet=%u dwErr=%u",
    917                                fRet, GetLastError()) );
    918     LogRel(("NEM: VidStopVirtualProcessor        -> fun:%#x in:%#x out:%#x\n", g_IoCtlStopVirtualProcessor.uFunction,
    919             g_IoCtlStopVirtualProcessor.cbInput, g_IoCtlStopVirtualProcessor.cbOutput));
    920 
    921     /* VidMessageSlotHandleAndGetNext */
    922     *g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_MessageSlotHandleAndGetNext;
    923     fRet = g_pfnVidMessageSlotHandleAndGetNext(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE,
    924                                                NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX, VID_MSHAGN_F_HANDLE_MESSAGE,
    925                                                NEM_WIN_IOCTL_DETECTOR_FAKE_TIMEOUT);
    926     *g_ppfnVidNtDeviceIoControlFile = pfnOrg;
    927     AssertReturn(fRet && g_IoCtlMessageSlotHandleAndGetNext.uFunction != 0,
    928                  RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED,
    929                                "Problem figuring out VidMessageSlotHandleAndGetNext: fRet=%u dwErr=%u",
    930                                fRet, GetLastError()) );
    931     LogRel(("NEM: VidMessageSlotHandleAndGetNext -> fun:%#x in:%#x out:%#x\n",
    932             g_IoCtlMessageSlotHandleAndGetNext.uFunction, g_IoCtlMessageSlotHandleAndGetNext.cbInput,
    933             g_IoCtlMessageSlotHandleAndGetNext.cbOutput));
    934 
    935 #ifdef LOG_ENABLED
    936     /* The following are only for logging: */
    937     union
    938     {
    939         VID_MAPPED_MESSAGE_SLOT MapSlot;
    940         HV_REGISTER_NAME        Name;
    941         HV_REGISTER_VALUE       Value;
    942     } uBuf;
    943 
    944     /* VidMessageSlotMap */
    945     g_pIoCtlDetectForLogging = &g_IoCtlMessageSlotMap;
    946     *g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_ForLogging;
    947     fRet = g_pfnVidMessageSlotMap(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, &uBuf.MapSlot, NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX);
    948     *g_ppfnVidNtDeviceIoControlFile = pfnOrg;
    949     Assert(fRet);
    950     LogRel(("NEM: VidMessageSlotMap              -> fun:%#x in:%#x out:%#x\n", g_pIoCtlDetectForLogging->uFunction,
    951             g_pIoCtlDetectForLogging->cbInput, g_pIoCtlDetectForLogging->cbOutput));
    952 
    953     /* VidGetVirtualProcessorState */
    954     uBuf.Name = HvRegisterExplicitSuspend;
    955     g_pIoCtlDetectForLogging = &g_IoCtlGetVirtualProcessorState;
    956     *g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_ForLogging;
    957     fRet = g_pfnVidGetVirtualProcessorState(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX,
    958                                             &uBuf.Name, 1, &uBuf.Value);
    959     *g_ppfnVidNtDeviceIoControlFile = pfnOrg;
    960     Assert(fRet);
    961     LogRel(("NEM: VidGetVirtualProcessorState    -> fun:%#x in:%#x out:%#x\n", g_pIoCtlDetectForLogging->uFunction,
    962             g_pIoCtlDetectForLogging->cbInput, g_pIoCtlDetectForLogging->cbOutput));
    963 
    964     /* VidSetVirtualProcessorState */
    965     uBuf.Name = HvRegisterExplicitSuspend;
    966     g_pIoCtlDetectForLogging = &g_IoCtlSetVirtualProcessorState;
    967     *g_ppfnVidNtDeviceIoControlFile = nemR3WinIoctlDetector_ForLogging;
    968     fRet = g_pfnVidSetVirtualProcessorState(NEM_WIN_IOCTL_DETECTOR_FAKE_HANDLE, NEM_WIN_IOCTL_DETECTOR_FAKE_VP_INDEX,
    969                                             &uBuf.Name, 1, &uBuf.Value);
    970     *g_ppfnVidNtDeviceIoControlFile = pfnOrg;
    971     Assert(fRet);
    972     LogRel(("NEM: VidSetVirtualProcessorState    -> fun:%#x in:%#x out:%#x\n", g_pIoCtlDetectForLogging->uFunction,
    973             g_pIoCtlDetectForLogging->cbInput, g_pIoCtlDetectForLogging->cbOutput));
    974 
    975     g_pIoCtlDetectForLogging = NULL;
    976 #endif
    977 
    978     /* Done. */
    979     pVM->nem.s.IoCtlGetHvPartitionId            = g_IoCtlGetHvPartitionId;
    980     pVM->nem.s.IoCtlStartVirtualProcessor       = g_IoCtlStartVirtualProcessor;
    981     pVM->nem.s.IoCtlStopVirtualProcessor        = g_IoCtlStopVirtualProcessor;
    982     pVM->nem.s.IoCtlMessageSlotHandleAndGetNext = g_IoCtlMessageSlotHandleAndGetNext;
    983     return VINF_SUCCESS;
    984 }
    985 
    986 
    987 /**
    988  * Creates and sets up a Hyper-V (exo) partition.
    989  *
    990  * @returns VBox status code.
    991  * @param   pVM                 The cross context VM structure.
    992  * @param   pErrInfo            Where to always return error info.
    993  */
    994 static int nemR3WinInitCreatePartition(PVM pVM, PRTERRINFO pErrInfo)
    995 {
    996     AssertReturn(!pVM->nem.s.hPartition,       RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER, "Wrong initalization order"));
    997     AssertReturn(!pVM->nem.s.hPartitionDevice, RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER, "Wrong initalization order"));
    998 
    999     /*
    1000      * Create the partition.
    1001      */
    1002     WHV_PARTITION_HANDLE hPartition;
    1003     HRESULT hrc = WHvCreatePartition(&hPartition);
    1004     if (FAILED(hrc))
    1005         return RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, "WHvCreatePartition failed with %Rhrc (Last=%#x/%u)",
    1006                              hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    1007 
    1008     int rc;
    1009 
    1010     /*
    1011      * Set partition properties, most importantly the CPU count.
    1012      */
    1013     /**
    1014      * @todo Someone at Microsoft please explain another weird API:
    1015      *  - Why this API doesn't take the WHV_PARTITION_PROPERTY_CODE value as an
    1016      *    argument rather than as part of the struct.  That is so weird if you've
    1017      *    used any other NT or windows API,  including WHvGetCapability().
    1018      *  - Why use PVOID when WHV_PARTITION_PROPERTY is what's expected.  We
    1019      *    technically only need 9 bytes for setting/getting
    1020      *    WHVPartitionPropertyCodeProcessorClFlushSize, but the API insists on 16. */
    1021     WHV_PARTITION_PROPERTY Property;
    1022     RT_ZERO(Property);
    1023     Property.PropertyCode   = WHvPartitionPropertyCodeProcessorCount;
    1024     Property.ProcessorCount = pVM->cCpus;
    1025     hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property));
    1026     if (SUCCEEDED(hrc))
    1027     {
    1028         RT_ZERO(Property);
    1029         Property.PropertyCode                  = WHvPartitionPropertyCodeExtendedVmExits;
    1030         Property.ExtendedVmExits.X64CpuidExit  = pVM->nem.s.fExtendedCpuIdExit;
    1031         Property.ExtendedVmExits.X64MsrExit    = pVM->nem.s.fExtendedMsrExit;
    1032         Property.ExtendedVmExits.ExceptionExit = pVM->nem.s.fExtendedXcptExit;
    1033         hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property));
    1034         if (SUCCEEDED(hrc))
    1035         {
    1036             /*
    1037              * We'll continue setup in nemR3NativeInitAfterCPUM.
    1038              */
    1039             pVM->nem.s.fCreatedEmts     = false;
    1040             pVM->nem.s.hPartition       = hPartition;
    1041             LogRel(("NEM: Created partition %p.\n", hPartition));
    1042             return VINF_SUCCESS;
    1043         }
    1044 
    1045         rc = RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED,
    1046                            "Failed setting WHvPartitionPropertyCodeExtendedVmExits to %'#RX64: %Rhrc",
    1047                            Property.ExtendedVmExits.AsUINT64, hrc);
    1048     }
    1049     else
    1050         rc = RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED,
    1051                            "Failed setting WHvPartitionPropertyCodeProcessorCount to %u: %Rhrc (Last=%#x/%u)",
    1052                            pVM->cCpus, hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    1053     WHvDeletePartition(hPartition);
    1054 
    1055     Assert(!pVM->nem.s.hPartitionDevice);
    1056     Assert(!pVM->nem.s.hPartition);
    1057     return rc;
    1058 }
    1059 
    1060 
    1061 /**
    1062  * Try initialize the native API.
    1063  *
    1064  * This may only do part of the job, more can be done in
    1065  * nemR3NativeInitAfterCPUM() and nemR3NativeInitCompleted().
    1066  *
    1067  * @returns VBox status code.
    1068  * @param   pVM             The cross context VM structure.
    1069  * @param   fFallback       Whether we're in fallback mode or use-NEM mode. In
    1070  *                          the latter we'll fail if we cannot initialize.
    1071  * @param   fForced         Whether the HMForced flag is set and we should
    1072  *                          fail if we cannot initialize.
    1073  */
    1074 int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced)
    1075 {
    1076     /*
    1077      * Error state.
    1078      * The error message will be non-empty on failure and 'rc' will be set too.
    1079      */
    1080     RTERRINFOSTATIC ErrInfo;
    1081     PRTERRINFO pErrInfo = RTErrInfoInitStatic(&ErrInfo);
    1082     int rc = nemR3WinInitProbeAndLoad(fForced, pErrInfo);
    1083     if (RT_SUCCESS(rc))
    1084     {
    1085         /*
    1086          * Check the capabilties of the hypervisor, starting with whether it's present.
    1087          */
    1088         rc = nemR3WinInitCheckCapabilities(pVM, pErrInfo);
    1089         if (RT_SUCCESS(rc))
    1090         {
    1091             /*
    1092              * Discover the VID I/O control function numbers we need.
    1093              */
    1094             rc = nemR3WinInitDiscoverIoControlProperties(pVM, pErrInfo);
    1095             if (RT_SUCCESS(rc))
    1096             {
    1097                 /*
    1098                  * Check out our ring-0 capabilities.
    1099                  */
    1100                 rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_NEM_INIT_VM, 0, NULL);
    1101                 if (RT_SUCCESS(rc))
    1102                 {
    1103                     /*
    1104                      * Create and initialize a partition.
    1105                      */
    1106                     rc = nemR3WinInitCreatePartition(pVM, pErrInfo);
    1107                     if (RT_SUCCESS(rc))
    1108                     {
    1109                         VM_SET_MAIN_EXECUTION_ENGINE(pVM, VM_EXEC_ENGINE_NATIVE_API);
    1110                         Log(("NEM: Marked active!\n"));
    1111                     }
    1112                 }
    1113             }
    1114         }
    1115     }
    1116 
    1117     /*
    1118      * We only fail if in forced mode, otherwise just log the complaint and return.
    1119      */
    1120     Assert(pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API || RTErrInfoIsSet(pErrInfo));
    1121     if (   (fForced || !fFallback)
    1122         && pVM->bMainExecutionEngine != VM_EXEC_ENGINE_NATIVE_API)
    1123         return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s", pErrInfo->pszMsg);
    1124 
    1125     if (RTErrInfoIsSet(pErrInfo))
    1126         LogRel(("NEM: Not available: %s\n", pErrInfo->pszMsg));
    1127     return VINF_SUCCESS;
    1128 }
    1129 
    1130 
    1131 /**
    1132  * This is called after CPUMR3Init is done.
    1133  *
    1134  * @returns VBox status code.
    1135  * @param   pVM                 The VM handle..
    1136  */
    1137 int nemR3NativeInitAfterCPUM(PVM pVM)
    1138 {
    1139     /*
    1140      * Validate sanity.
    1141      */
    1142     WHV_PARTITION_HANDLE hPartition = pVM->nem.s.hPartition;
    1143     AssertReturn(hPartition != NULL, VERR_WRONG_ORDER);
    1144     AssertReturn(!pVM->nem.s.hPartitionDevice, VERR_WRONG_ORDER);
    1145     AssertReturn(!pVM->nem.s.fCreatedEmts, VERR_WRONG_ORDER);
    1146     AssertReturn(pVM->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API, VERR_WRONG_ORDER);
    1147 
    1148     /*
    1149      * Continue setting up the partition now that we've got most of the CPUID feature stuff.
    1150      */
    1151 
    1152     /* Not sure if we really need to set the vendor. */
    1153     WHV_PARTITION_PROPERTY Property;
    1154     RT_ZERO(Property);
    1155     Property.PropertyCode    = WHvPartitionPropertyCodeProcessorVendor;
    1156     Property.ProcessorVendor = pVM->nem.s.enmCpuVendor == CPUMCPUVENDOR_AMD ? WHvProcessorVendorAmd
    1157                              : WHvProcessorVendorIntel;
    1158     HRESULT hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property));
    1159     if (FAILED(hrc))
    1160         return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1161                           "Failed to set WHvPartitionPropertyCodeProcessorVendor to %u: %Rhrc (Last=%#x/%u)",
    1162                           Property.ProcessorVendor, hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    1163 
    1164     /* Not sure if we really need to set the cache line flush size. */
    1165     RT_ZERO(Property);
    1166     Property.PropertyCode         = WHvPartitionPropertyCodeProcessorClFlushSize;
    1167     Property.ProcessorClFlushSize = pVM->nem.s.cCacheLineFlushShift;
    1168     hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property));
    1169     if (FAILED(hrc))
    1170         return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1171                           "Failed to set WHvPartitionPropertyCodeProcessorClFlushSize to %u: %Rhrc (Last=%#x/%u)",
    1172                           pVM->nem.s.cCacheLineFlushShift, hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    1173 
    1174     /*
    1175      * Sync CPU features with CPUM.
    1176      */
    1177     /** @todo sync CPU features with CPUM. */
    1178 
    1179     /* Set the partition property. */
    1180     RT_ZERO(Property);
    1181     Property.PropertyCode               = WHvPartitionPropertyCodeProcessorFeatures;
    1182     Property.ProcessorFeatures.AsUINT64 = pVM->nem.s.uCpuFeatures.u64;
    1183     hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property));
    1184     if (FAILED(hrc))
    1185         return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1186                           "Failed to set WHvPartitionPropertyCodeProcessorFeatures to %'#RX64: %Rhrc (Last=%#x/%u)",
    1187                           pVM->nem.s.uCpuFeatures.u64, hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    1188 
    1189     /*
    1190      * Set up the partition and create EMTs.
    1191      *
    1192      * Seems like this is where the partition is actually instantiated and we get
    1193      * a handle to it.
    1194      */
    1195     hrc = WHvSetupPartition(hPartition);
    1196     if (FAILED(hrc))
    1197         return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1198                           "Call to WHvSetupPartition failed: %Rhrc (Last=%#x/%u)",
    1199                           hrc, RTNtLastStatusValue(), RTNtLastErrorValue());
    1200 
    1201     /* Get the handle. */
    1202     HANDLE hPartitionDevice;
    1203     __try
    1204     {
    1205         hPartitionDevice = ((HANDLE *)hPartition)[1];
    1206     }
    1207     __except(EXCEPTION_EXECUTE_HANDLER)
    1208     {
    1209         hrc = GetExceptionCode();
    1210         hPartitionDevice = NULL;
    1211     }
    1212     if (   hPartitionDevice == NULL
    1213         || hPartitionDevice == (HANDLE)(intptr_t)-1)
    1214         return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1215                           "Failed to get device handle for partition %p: %Rhrc", hPartition, hrc);
    1216 
    1217     HV_PARTITION_ID idHvPartition = HV_PARTITION_ID_INVALID;
    1218     if (!g_pfnVidGetHvPartitionId(hPartitionDevice, &idHvPartition))
    1219         return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1220                           "Failed to get device handle and/or partition ID for %p (hPartitionDevice=%p, Last=%#x/%u)",
    1221                           hPartition, hPartitionDevice, RTNtLastStatusValue(), RTNtLastErrorValue());
    1222     pVM->nem.s.hPartitionDevice = hPartitionDevice;
    1223     pVM->nem.s.idHvPartition    = idHvPartition;
    1224 
    1225     /*
    1226      * Setup the EMTs.
    1227      */
    1228     VMCPUID iCpu;
    1229     for (iCpu = 0; iCpu < pVM->cCpus; iCpu++)
    1230     {
    1231         PVMCPU pVCpu = &pVM->aCpus[iCpu];
    1232 
    1233         pVCpu->nem.s.hNativeThreadHandle = (RTR3PTR)RTThreadGetNativeHandle(VMR3GetThreadHandle(pVCpu->pUVCpu));
    1234         Assert((HANDLE)pVCpu->nem.s.hNativeThreadHandle != INVALID_HANDLE_VALUE);
    1235 
    1236 #ifdef NEM_WIN_USE_OUR_OWN_RUN_API
    1237         VID_MAPPED_MESSAGE_SLOT MappedMsgSlot = { NULL, UINT32_MAX, UINT32_MAX };
    1238         if (g_pfnVidMessageSlotMap(hPartitionDevice, &MappedMsgSlot, iCpu))
    1239         {
    1240             AssertLogRelMsg(MappedMsgSlot.iCpu == iCpu && MappedMsgSlot.uParentAdvisory == UINT32_MAX,
    1241                             ("%#x %#x (iCpu=%#x)\n", MappedMsgSlot.iCpu, MappedMsgSlot.uParentAdvisory, iCpu));
    1242             pVCpu->nem.s.pvMsgSlotMapping = MappedMsgSlot.pMsgBlock;
    1243         }
    1244         else
    1245         {
    1246             NTSTATUS const rcNtLast  = RTNtLastStatusValue();
    1247             DWORD const    dwErrLast = RTNtLastErrorValue();
    1248             return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1249                               "Call to WHvSetupPartition failed: %Rhrc (Last=%#x/%u)", hrc, rcNtLast, dwErrLast);
    1250         }
    1251 #else
    1252         hrc = WHvCreateVirtualProcessor(hPartition, iCpu, 0 /*fFlags*/);
    1253         if (FAILED(hrc))
    1254         {
    1255             NTSTATUS const rcNtLast  = RTNtLastStatusValue();
    1256             DWORD const    dwErrLast = RTNtLastErrorValue();
    1257             while (iCpu-- > 0)
    1258             {
    1259                 HRESULT hrc2 = WHvDeleteVirtualProcessor(hPartition, iCpu);
    1260                 AssertLogRelMsg(SUCCEEDED(hrc2), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc (Last=%#x/%u)\n",
    1261                                                   hPartition, iCpu, hrc2, RTNtLastStatusValue(),
    1262                                                   RTNtLastErrorValue()));
    1263             }
    1264             return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS,
    1265                               "Call to WHvSetupPartition failed: %Rhrc (Last=%#x/%u)", hrc, rcNtLast, dwErrLast);
    1266         }
    1267 #endif /* !NEM_WIN_USE_OUR_OWN_RUN_API */
    1268     }
    1269     pVM->nem.s.fCreatedEmts = true;
    1270 
    1271     /*
    1272      * Do some more ring-0 initialization now that we've got the partition handle.
    1273      */
    1274     int rc = VMMR3CallR0Emt(pVM, &pVM->aCpus[0], VMMR0_DO_NEM_INIT_VM_PART_2, 0, NULL);
    1275     if (RT_SUCCESS(rc))
    1276     {
    1277         LogRel(("NEM: Successfully set up partition (device handle %p, partition ID %#llx)\n", hPartitionDevice, idHvPartition));
    1278         return VINF_SUCCESS;
    1279     }
    1280     return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Call to NEMR0InitVMPart2 failed: %Rrc", rc);
    1281 }
    1282 
    1283 
    1284 int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
    1285 {
    1286     NOREF(pVM); NOREF(enmWhat);
    1287     return VINF_SUCCESS;
    1288 }
    1289 
    1290 
    1291 int nemR3NativeTerm(PVM pVM)
    1292 {
    1293     /*
    1294      * Delete the partition.
    1295      */
    1296     WHV_PARTITION_HANDLE hPartition = pVM->nem.s.hPartition;
    1297     pVM->nem.s.hPartition       = NULL;
    1298     pVM->nem.s.hPartitionDevice = NULL;
    1299     if (hPartition != NULL)
    1300     {
    1301         VMCPUID iCpu = pVM->nem.s.fCreatedEmts ? pVM->cCpus : 0;
    1302         LogRel(("NEM: Destroying partition %p with its %u VCpus...\n", hPartition, iCpu));
    1303         while (iCpu-- > 0)
    1304         {
    1305 #ifdef NEM_WIN_USE_OUR_OWN_RUN_API
    1306             pVM->aCpus[iCpu].nem.s.pvMsgSlotMapping = NULL;
    1307 #else
    1308             HRESULT hrc = WHvDeleteVirtualProcessor(hPartition, iCpu);
    1309             AssertLogRelMsg(SUCCEEDED(hrc), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc (Last=%#x/%u)\n",
    1310                                              hPartition, iCpu, hrc, RTNtLastStatusValue(),
    1311                                              RTNtLastErrorValue()));
    1312 #endif
    1313         }
    1314         WHvDeletePartition(hPartition);
    1315     }
    1316     pVM->nem.s.fCreatedEmts = false;
    1317     return VINF_SUCCESS;
    1318 }
    1319 
    1320 
    1321 /**
    1322  * VM reset notification.
    1323  *
    1324  * @param   pVM         The cross context VM structure.
    1325  */
    1326 void nemR3NativeReset(PVM pVM)
    1327 {
    1328     /* Unfix the A20 gate. */
    1329     pVM->nem.s.fA20Fixed = false;
    1330 }
    1331 
    1332 
    1333 /**
    1334  * Reset CPU due to INIT IPI or hot (un)plugging.
    1335  *
    1336  * @param   pVCpu       The cross context virtual CPU structure of the CPU being
    1337  *                      reset.
    1338  * @param   fInitIpi    Whether this is the INIT IPI or hot (un)plugging case.
    1339  */
    1340 void nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi)
    1341 {
    1342     /* Lock the A20 gate if INIT IPI, make sure it's enabled.  */
    1343     if (fInitIpi && pVCpu->idCpu > 0)
    1344     {
    1345         PVM pVM = pVCpu->CTX_SUFF(pVM);
    1346         if (!pVM->nem.s.fA20Enabled)
    1347             nemR3NativeNotifySetA20(pVCpu, true);
    1348         pVM->nem.s.fA20Enabled = true;
    1349         pVM->nem.s.fA20Fixed   = true;
    1350     }
    1351 }
     29NEM_TMPL_STATIC int nemHCNativeSetPhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst,
     30                                           uint32_t fPageProt, uint8_t *pu2State, bool fBackingChanged);
     31
    135232
    135333#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
     
    136444 * @param   fFlags      HV_MAP_GPA_XXX.
    136545 */
    1366 DECLINLINE(int) nemR3WinHypercallMapPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst, uint32_t fFlags)
    1367 {
     46DECLINLINE(int) nemHCWinHypercallMapPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst, uint32_t fFlags)
     47{
     48#ifdef IN_RING0
     49    /** @todo optimize further, caller generally has the physical address. */
     50    PGVM pGVM = GVMMR0FastGetGVMByVM(pVM);
     51    AssertReturn(pGVM, VERR_INVALID_VM_HANDLE);
     52    return nemR0WinMapPages(pGVM, pVM, &pGVM->aCpus[pVCpu->idCpu], GCPhysSrc, GCPhysDst, 1, fFlags);
     53#else
    136854    pVCpu->nem.s.Hypercall.MapPages.GCPhysSrc   = GCPhysSrc & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK;
    136955    pVCpu->nem.s.Hypercall.MapPages.GCPhysDst   = GCPhysDst & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK;
     
    137157    pVCpu->nem.s.Hypercall.MapPages.fFlags      = fFlags;
    137258    return VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_MAP_PAGES, 0, NULL);
     59#endif
    137360}
    137461
     
    138269 * @param   GCPhys      The page to unmap.  Does not need to be page aligned.
    138370 */
    1384 DECLINLINE(int) nemR3WinHypercallUnmapPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
    1385 {
     71DECLINLINE(int) nemHCWinHypercallUnmapPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
     72{
     73# ifdef IN_RING0
     74    PGVM pGVM = GVMMR0FastGetGVMByVM(pVM);
     75    AssertReturn(pGVM, VERR_INVALID_VM_HANDLE);
     76    return nemR0WinUnmapPages(pGVM, &pGVM->aCpus[pVCpu->idCpu], GCPhys, 1);
     77# else
    138678    pVCpu->nem.s.Hypercall.UnmapPages.GCPhys    = GCPhys & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK;
    138779    pVCpu->nem.s.Hypercall.UnmapPages.cPages    = 1;
    138880    return VMMR3CallR0Emt(pVM, pVCpu, VMMR0_DO_NEM_UNMAP_PAGES, 0, NULL);
     81# endif
    138982}
    139083
    139184#endif /* NEM_WIN_USE_HYPERCALLS_FOR_PAGES */
    139285
    1393 static int nemR3WinCopyStateToHyperV(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
     86
     87#ifndef IN_RING0
     88
     89NEM_TMPL_STATIC int nemHCWinCopyStateToHyperV(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
    139490{
    139591#ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     
    1692388}
    1693389
    1694 static int nemR3WinCopyStateFromHyperV(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
     390
     391NEM_TMPL_STATIC int nemHCWinCopyStateFromHyperV(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
    1695392{
    1696393#ifdef NEM_WIN_USE_HYPERCALLS_FOR_REGISTERS
     
    2070767 * Get the virtual processor running status.
    2071768 */
    2072 DECLINLINE(VID_PROCESSOR_STATUS) nemR3WinCpuGetRunningStatus(PVMCPU pVCpu)
    2073 {
     769DECLINLINE(VID_PROCESSOR_STATUS) nemHCWinCpuGetRunningStatus(PVMCPU pVCpu)
     770{
     771# ifdef IN_RING0
     772    NOREF(pVCpu);
     773    return VidProcessorStatusUndefined;
     774# else
    2074775    RTERRVARS Saved;
    2075776    RTErrVarsSave(&Saved);
     
    2085786    RTErrVarsRestore(&Saved);
    2086787    return enmCpuStatus;
     788# endif
    2087789}
    2088790#endif
     
    2091793#ifdef NEM_WIN_USE_OUR_OWN_RUN_API
    2092794
     795# ifdef IN_RING3 /* hopefully not needed in ring-0, as we'd need KTHREADs and KeAlertThread. */
    2093796/**
    2094797 * Our own WHvCancelRunVirtualProcessor that can later be moved to ring-0.
     
    2101804 *                          calling EMT.
    2102805 */
    2103 static int nemR3WinCancelRunVirtualProcessor(PVM pVM, PVMCPU pVCpu)
     806NEM_TMPL_STATIC int nemHCWinCancelRunVirtualProcessor(PVM pVM, PVMCPU pVCpu)
    2104807{
    2105808    /*
     
    2118821                if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED, VMCPUSTATE_STARTED_EXEC_NEM))
    2119822                {
    2120                     Log8(("nemR3WinCancelRunVirtualProcessor: Switched %u to canceled state\n", pVCpu->idCpu));
     823                    Log8(("nemHCWinCancelRunVirtualProcessor: Switched %u to canceled state\n", pVCpu->idCpu));
    2121824                    return VINF_SUCCESS;
    2122825                }
     
    2126829                if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED, VMCPUSTATE_STARTED_EXEC_NEM_WAIT))
    2127830                {
     831#  ifdef IN_RING0
     832                    NTSTATUS rcNt = KeAlertThread(??);
     833#  else
    2128834                    NTSTATUS rcNt = NtAlertThread(pVCpu->nem.s.hNativeThreadHandle);
    2129                     Log8(("nemR3WinCancelRunVirtualProcessor: Alerted %u: %#x\n", pVCpu->idCpu, rcNt));
     835#  endif
     836                    Log8(("nemHCWinCancelRunVirtualProcessor: Alerted %u: %#x\n", pVCpu->idCpu, rcNt));
    2130837                    Assert(rcNt == STATUS_SUCCESS);
    2131838                    if (NT_SUCCESS(rcNt))
     
    2143850    }
    2144851}
     852# endif /* IN_RING3 */
    2145853
    2146854
     
    2148856 * Fills in WHV_VP_EXIT_CONTEXT from HV_X64_INTERCEPT_MESSAGE_HEADER.
    2149857 */
    2150 DECLINLINE(void) nemR3WinConvertX64MsgHdrToVpExitCtx(HV_X64_INTERCEPT_MESSAGE_HEADER const *pHdr, WHV_VP_EXIT_CONTEXT *pCtx)
     858DECLINLINE(void) nemHCWinConvertX64MsgHdrToVpExitCtx(HV_X64_INTERCEPT_MESSAGE_HEADER const *pHdr, WHV_VP_EXIT_CONTEXT *pCtx)
    2151859{
    2152860    pCtx->ExecutionState.AsUINT16   = pHdr->ExecutionState.AsUINT16;
     
    2168876 * @param   pExitCtx        The output structure. Assumes zeroed.
    2169877 */
    2170 static int nemR3WinRunVirtualProcessorConvertPending(HV_MESSAGE_HEADER const *pMsgHdr, WHV_RUN_VP_EXIT_CONTEXT *pExitCtx)
     878NEM_TMPL_STATIC int nemHCWinRunVirtualProcessorConvertPending(HV_MESSAGE_HEADER const *pMsgHdr, WHV_RUN_VP_EXIT_CONTEXT *pExitCtx)
    2171879{
    2172880    switch (pMsgHdr->MessageType)
     
    2179887
    2180888            pExitCtx->ExitReason                            = WHvRunVpExitReasonMemoryAccess;
    2181             nemR3WinConvertX64MsgHdrToVpExitCtx(&pMemMsg->Header, &pExitCtx->MemoryAccess.VpContext);
     889            nemHCWinConvertX64MsgHdrToVpExitCtx(&pMemMsg->Header, &pExitCtx->MemoryAccess.VpContext);
    2182890            pExitCtx->MemoryAccess.InstructionByteCount     = pMemMsg->InstructionByteCount;
    2183891            ((uint64_t *)pExitCtx->MemoryAccess.InstructionBytes)[0] = ((uint64_t const *)pMemMsg->InstructionBytes)[0];
     
    2199907
    2200908            pExitCtx->ExitReason                            = WHvRunVpExitReasonX64IoPortAccess;
    2201             nemR3WinConvertX64MsgHdrToVpExitCtx(&pPioMsg->Header, &pExitCtx->IoPortAccess.VpContext);
     909            nemHCWinConvertX64MsgHdrToVpExitCtx(&pPioMsg->Header, &pExitCtx->IoPortAccess.VpContext);
    2202910            pExitCtx->IoPortAccess.InstructionByteCount     = pPioMsg->InstructionByteCount;
    2203911            ((uint64_t *)pExitCtx->IoPortAccess.InstructionBytes)[0] = ((uint64_t const *)pPioMsg->InstructionBytes)[0];
     
    2272980 * @param   cbExitCtx       Size of the exit information area.
    2273981 */
    2274 static int nemR3WinRunVirtualProcessor(PVM pVM, PVMCPU pVCpu, WHV_RUN_VP_EXIT_CONTEXT *pExitCtx, size_t cbExitCtx)
     982NEM_TMPL_STATIC int nemHCWinRunVirtualProcessor(PVM pVM, PVMCPU pVCpu, WHV_RUN_VP_EXIT_CONTEXT *pExitCtx, size_t cbExitCtx)
    2275983{
    2276984    RT_BZERO(pExitCtx, cbExitCtx);
     
    2288996            Assert(pMappingHeader->enmVidMsgType == VidMessageHypervisorMessage);
    2289997            fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE | VID_MSHAGN_F_HANDLE_MESSAGE;
    2290             Log8(("nemR3WinRunVirtualProcessor: #1: msg pending, no need to start CPU (cpu state %u)\n", nemR3WinCpuGetRunningStatus(pVCpu) ));
     998            Log8(("nemHCWinRunVirtualProcessor: #1: msg pending, no need to start CPU (cpu state %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    2291999        }
    22921000        else if (bMsgState != NEM_WIN_MSG_STATE_STARTED)
     
    22941002            if (bMsgState == NEM_WIN_MSG_STATE_PENDING_STOP_AND_MSG)
    22951003            {
    2296                 Log8(("nemR3WinRunVirtualProcessor: #0: pending stop+message (cpu status %u)\n", nemR3WinCpuGetRunningStatus(pVCpu) ));
     1004                Log8(("nemHCWinRunVirtualProcessor: #0: pending stop+message (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    22971005                /* ACK the pending message and get the stop message. */
    22981006                BOOL fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
     
    23081016            }
    23091017
    2310             Log8(("nemR3WinRunVirtualProcessor: #1: starting CPU (cpu status %u)\n", nemR3WinCpuGetRunningStatus(pVCpu) ));
     1018            Log8(("nemHCWinRunVirtualProcessor: #1: starting CPU (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    23111019            if (g_pfnVidStartVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu))
    23121020                pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STARTED;
     
    23241032            /* This shouldn't happen. */
    23251033            fHandleAndGetFlags = VID_MSHAGN_F_GET_NEXT_MESSAGE;
    2326             Log8(("nemR3WinRunVirtualProcessor: #1: NO MSG PENDING! No need to start CPU (cpu state %u)\n", nemR3WinCpuGetRunningStatus(pVCpu) ));
     1034            Log8(("nemHCWinRunVirtualProcessor: #1: NO MSG PENDING! No need to start CPU (cpu state %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    23271035        }
    23281036    }
    23291037    else
    23301038    {
    2331         Log8(("nemR3WinRunVirtualProcessor: #1: state=%u -> canceled (cpu status %u)\n",
    2332               VMCPU_GET_STATE(pVCpu), nemR3WinCpuGetRunningStatus(pVCpu)));
     1039        Log8(("nemHCWinRunVirtualProcessor: #1: state=%u -> canceled (cpu status %u)\n",
     1040              VMCPU_GET_STATE(pVCpu), nemHCWinCpuGetRunningStatus(pVCpu)));
    23331041        pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
    23341042        return VINF_SUCCESS;
     
    23431051        if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM_WAIT, VMCPUSTATE_STARTED_EXEC_NEM))
    23441052        {
    2345             Log8(("nemR3WinRunVirtualProcessor: #2: Waiting %#x (cpu status %u)...\n",
    2346                   fHandleAndGetFlags, nemR3WinCpuGetRunningStatus(pVCpu)));
     1053            Log8(("nemHCWinRunVirtualProcessor: #2: Waiting %#x (cpu status %u)...\n",
     1054                  fHandleAndGetFlags, nemHCWinCpuGetRunningStatus(pVCpu)));
    23471055            BOOL fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu,
    23481056                                                             fHandleAndGetFlags, cMillies);
     
    23561064                    if (!VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_WAIT))
    23571065                        VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
    2358                     Log8(("nemR3WinRunVirtualProcessor: #3: wait succeeded: %#x / %#x (cpu status %u)\n",
     1066                    Log8(("nemHCWinRunVirtualProcessor: #3: wait succeeded: %#x / %#x (cpu status %u)\n",
    23591067                          enmVidMsgType, ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType,
    2360                           nemR3WinCpuGetRunningStatus(pVCpu) ));
     1068                          nemHCWinCpuGetRunningStatus(pVCpu) ));
    23611069                    pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_PENDING_MSG;
    2362                     return nemR3WinRunVirtualProcessorConvertPending((HV_MESSAGE_HEADER const *)(pMappingHeader + 1), pExitCtx);
     1070                    return nemHCWinRunVirtualProcessorConvertPending((HV_MESSAGE_HEADER const *)(pMappingHeader + 1), pExitCtx);
    23631071                }
    23641072
     
    23681076                __debugbreak();
    23691077#endif
    2370                 Log8(("nemR3WinRunVirtualProcessor: #3: wait succeeded, but nothing pending: %#x / %#x (cpu status %u)\n",
    2371                       enmVidMsgType, ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemR3WinCpuGetRunningStatus(pVCpu) ));
     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) ));
    23721080                pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STARTED;
    23731081                AssertLogRelMsgReturnStmt(enmVidMsgType == VidMessageStopRequestComplete,
     
    23851093                AssertLogRelMsgReturnStmt(   dwErr == STATUS_TIMEOUT
    23861094                                          || dwErr == STATUS_ALERTED || dwErr == STATUS_USER_APC, /* just in case */
    2387                                           ("dwErr=%u (%#x) (cpu status %u)\n", dwErr, dwErr, nemR3WinCpuGetRunningStatus(pVCpu)),
     1095                                          ("dwErr=%u (%#x) (cpu status %u)\n", dwErr, dwErr, nemHCWinCpuGetRunningStatus(pVCpu)),
    23881096                                          g_pfnVidStopVirtualProcessor(pVM->nem.s.hPartitionDevice, pVCpu->idCpu),
    23891097                                          VERR_INTERNAL_ERROR_3);
    2390                 Log8(("nemR3WinRunVirtualProcessor: #3: wait timed out (cpu status %u)\n", nemR3WinCpuGetRunningStatus(pVCpu) ));
     1098                Log8(("nemHCWinRunVirtualProcessor: #3: wait timed out (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    23911099                pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STARTED;
    23921100                fHandleAndGetFlags &= ~VID_MSHAGN_F_HANDLE_MESSAGE;
     
    24011109             * return, and that can be a bit complicated.
    24021110             */
    2403             Log8(("nemR3WinRunVirtualProcessor: #4: state changed to %u (cpu status %u)\n",
    2404                   VMCPU_GET_STATE(pVCpu), nemR3WinCpuGetRunningStatus(pVCpu) ));
     1111            Log8(("nemHCWinRunVirtualProcessor: #4: state changed to %u (cpu status %u)\n",
     1112                  VMCPU_GET_STATE(pVCpu), nemHCWinCpuGetRunningStatus(pVCpu) ));
    24051113            VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED, VMCPUSTATE_STARTED_EXEC_NEM_CANCELED);
    24061114
     
    24091117            if (fHandleAndGetFlags & VID_MSHAGN_F_HANDLE_MESSAGE)
    24101118            {
    2411                 Log8(("nemR3WinRunVirtualProcessor: #5: Didn't resume previous message.\n"));
     1119                Log8(("nemHCWinRunVirtualProcessor: #5: Didn't resume previous message.\n"));
    24121120                pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_PENDING_MSG;
    24131121                pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
     
    24191127            if (fStop)
    24201128            {
    2421                 Log8(("nemR3WinRunVirtualProcessor: #5: Stopping CPU succeeded (cpu status %u)\n", nemR3WinCpuGetRunningStatus(pVCpu) ));
     1129                Log8(("nemHCWinRunVirtualProcessor: #5: Stopping CPU succeeded (cpu status %u)\n", nemHCWinCpuGetRunningStatus(pVCpu) ));
    24221130                pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_STOPPED;
    24231131                pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
     
    24271135            /* Dang, the CPU stopped by itself with a message pending. */
    24281136            DWORD dwErr = RTNtLastErrorValue();
    2429             Log8(("nemR3WinRunVirtualProcessor: #5: Stopping CPU failed (%u/%#x) - cpu status %u\n",
    2430                   dwErr, dwErr, nemR3WinCpuGetRunningStatus(pVCpu) ));
     1137            Log8(("nemHCWinRunVirtualProcessor: #5: Stopping CPU failed (%u/%#x) - cpu status %u\n",
     1138                  dwErr, dwErr, nemHCWinCpuGetRunningStatus(pVCpu) ));
    24311139            pExitCtx->ExitReason = WHvRunVpExitReasonCanceled;
    24321140            AssertLogRelMsgReturn(dwErr == ERROR_VID_STOP_PENDING, ("dwErr=%#u\n", dwErr), VERR_INTERNAL_ERROR_3);
     
    24401148            if (enmVidMsgType == VidMessageHypervisorMessage)
    24411149            {
    2442                 Log8(("nemR3WinRunVirtualProcessor: #6: wait succeeded: %#x / %#x (cpu status %u)\n", enmVidMsgType,
    2443                       ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemR3WinCpuGetRunningStatus(pVCpu) ));
     1150                Log8(("nemHCWinRunVirtualProcessor: #6: wait succeeded: %#x / %#x (cpu status %u)\n", enmVidMsgType,
     1151                      ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemHCWinCpuGetRunningStatus(pVCpu) ));
    24441152                pVCpu->nem.s.bMsgState = NEM_WIN_MSG_STATE_PENDING_STOP_AND_MSG;
    2445                 return nemR3WinRunVirtualProcessorConvertPending((HV_MESSAGE_HEADER const *)(pMappingHeader + 1), pExitCtx);
     1153                return nemHCWinRunVirtualProcessorConvertPending((HV_MESSAGE_HEADER const *)(pMappingHeader + 1), pExitCtx);
    24461154            }
    24471155
    24481156            /* ACK the stop message, if that's what it is.  Don't think we'll ever get here. */
    2449             Log8(("nemR3WinRunVirtualProcessor: #6b: wait succeeded: %#x / %#x (cpu status %u)\n", enmVidMsgType,
    2450                   ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemR3WinCpuGetRunningStatus(pVCpu) ));
     1157            Log8(("nemHCWinRunVirtualProcessor: #6b: wait succeeded: %#x / %#x (cpu status %u)\n", enmVidMsgType,
     1158                  ((HV_MESSAGE_HEADER const *)(pMappingHeader + 1))->MessageType, nemHCWinCpuGetRunningStatus(pVCpu) ));
    24511159            AssertLogRelMsgReturn(enmVidMsgType == VidMessageStopRequestComplete, ("enmVidMsgType=%#x\n", enmVidMsgType),
    24521160                                  VERR_INTERNAL_ERROR_3);
     
    24671175
    24681176#ifdef LOG_ENABLED
    2469 
    2470 /**
    2471  * Log the full details of an exit reason.
    2472  *
    2473  * @param   pExitReason     The exit reason to log.
    2474  */
    2475 static void nemR3WinLogExitReason(WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    2476 {
    2477     bool fExitCtx = false;
    2478     bool fExitInstr = false;
    2479     switch (pExitReason->ExitReason)
    2480     {
    2481         case WHvRunVpExitReasonMemoryAccess:
    2482             Log2(("Exit: Memory access: GCPhys=%RGp GCVirt=%RGv %s %s %s\n",
    2483                   pExitReason->MemoryAccess.Gpa, pExitReason->MemoryAccess.Gva,
    2484                   g_apszWHvMemAccesstypes[pExitReason->MemoryAccess.AccessInfo.AccessType],
    2485                   pExitReason->MemoryAccess.AccessInfo.GpaUnmapped ? "unmapped" : "mapped",
    2486                   pExitReason->MemoryAccess.AccessInfo.GvaValid    ? "" : "invalid-gc-virt"));
    2487             AssertMsg(!(pExitReason->MemoryAccess.AccessInfo.AsUINT32 & ~UINT32_C(0xf)),
    2488                       ("MemoryAccess.AccessInfo=%#x\n", pExitReason->MemoryAccess.AccessInfo.AsUINT32));
    2489             fExitCtx = fExitInstr = true;
    2490             break;
    2491 
    2492         case WHvRunVpExitReasonX64IoPortAccess:
    2493             Log2(("Exit: I/O port access: IoPort=%#x LB %u %s%s%s rax=%#RX64 rcx=%#RX64 rsi=%#RX64 rdi=%#RX64\n",
    2494                   pExitReason->IoPortAccess.PortNumber,
    2495                   pExitReason->IoPortAccess.AccessInfo.AccessSize,
    2496                   pExitReason->IoPortAccess.AccessInfo.IsWrite ? "out" : "in",
    2497                   pExitReason->IoPortAccess.AccessInfo.StringOp ? " string" : "",
    2498                   pExitReason->IoPortAccess.AccessInfo.RepPrefix ? " rep" : "",
    2499                   pExitReason->IoPortAccess.Rax,
    2500                   pExitReason->IoPortAccess.Rcx,
    2501                   pExitReason->IoPortAccess.Rsi,
    2502                   pExitReason->IoPortAccess.Rdi));
    2503             Log2(("Exit: + ds=%#x:{%#RX64 LB %#RX32, %#x}  es=%#x:{%#RX64 LB %#RX32, %#x}\n",
    2504                   pExitReason->IoPortAccess.Ds.Selector,
    2505                   pExitReason->IoPortAccess.Ds.Base,
    2506                   pExitReason->IoPortAccess.Ds.Limit,
    2507                   pExitReason->IoPortAccess.Ds.Attributes,
    2508                   pExitReason->IoPortAccess.Es.Selector,
    2509                   pExitReason->IoPortAccess.Es.Base,
    2510                   pExitReason->IoPortAccess.Es.Limit,
    2511                   pExitReason->IoPortAccess.Es.Attributes ));
    2512 
    2513             AssertMsg(   pExitReason->IoPortAccess.AccessInfo.AccessSize == 1
    2514                       || pExitReason->IoPortAccess.AccessInfo.AccessSize == 2
    2515                       || pExitReason->IoPortAccess.AccessInfo.AccessSize == 4,
    2516                       ("IoPortAccess.AccessInfo.AccessSize=%d\n", pExitReason->IoPortAccess.AccessInfo.AccessSize));
    2517             AssertMsg(!(pExitReason->IoPortAccess.AccessInfo.AsUINT32 & ~UINT32_C(0x3f)),
    2518                       ("IoPortAccess.AccessInfo=%#x\n", pExitReason->IoPortAccess.AccessInfo.AsUINT32));
    2519             fExitCtx = fExitInstr = true;
    2520             break;
    2521 
    2522 # if 0
    2523         case WHvRunVpExitReasonUnrecoverableException:
    2524         case WHvRunVpExitReasonInvalidVpRegisterValue:
    2525         case WHvRunVpExitReasonUnsupportedFeature:
    2526         case WHvRunVpExitReasonX64InterruptWindow:
    2527         case WHvRunVpExitReasonX64Halt:
    2528         case WHvRunVpExitReasonX64MsrAccess:
    2529         case WHvRunVpExitReasonX64Cpuid:
    2530         case WHvRunVpExitReasonException:
    2531         case WHvRunVpExitReasonCanceled:
    2532         case WHvRunVpExitReasonAlerted:
    2533             WHV_X64_MSR_ACCESS_CONTEXT MsrAccess;
    2534             WHV_X64_CPUID_ACCESS_CONTEXT CpuidAccess;
    2535             WHV_VP_EXCEPTION_CONTEXT VpException;
    2536             WHV_X64_INTERRUPTION_DELIVERABLE_CONTEXT InterruptWindow;
    2537             WHV_UNRECOVERABLE_EXCEPTION_CONTEXT UnrecoverableException;
    2538             WHV_X64_UNSUPPORTED_FEATURE_CONTEXT UnsupportedFeature;
    2539             WHV_RUN_VP_CANCELED_CONTEXT CancelReason;
    2540 #endif
    2541 
    2542         case WHvRunVpExitReasonNone:
    2543             Log2(("Exit: No reason\n"));
    2544             AssertFailed();
    2545             break;
    2546 
    2547         default:
    2548             Log(("Exit: %#x\n", pExitReason->ExitReason));
    2549             break;
    2550     }
    2551 
    2552     /*
    2553      * Context and maybe instruction details.
    2554      */
    2555     if (fExitCtx)
    2556     {
    2557         const WHV_VP_EXIT_CONTEXT *pVpCtx = &pExitReason->IoPortAccess.VpContext;
    2558         Log2(("Exit: + CS:RIP=%04x:%08RX64 RFLAGS=%06RX64 cbInstr=%u CS={%RX64 L %#RX32, %#x}\n",
    2559               pVpCtx->Cs.Selector,
    2560               pVpCtx->Rip,
    2561               pVpCtx->Rflags,
    2562               pVpCtx->InstructionLength,
    2563               pVpCtx->Cs.Base, pVpCtx->Cs.Limit, pVpCtx->Cs.Attributes));
    2564         Log2(("Exit: + cpl=%d CR0.PE=%d CR0.AM=%d EFER.LMA=%d DebugActive=%d InterruptionPending=%d InterruptShadow=%d\n",
    2565               pVpCtx->ExecutionState.Cpl,
    2566               pVpCtx->ExecutionState.Cr0Pe,
    2567               pVpCtx->ExecutionState.Cr0Am,
    2568               pVpCtx->ExecutionState.EferLma,
    2569               pVpCtx->ExecutionState.DebugActive,
    2570               pVpCtx->ExecutionState.InterruptionPending,
    2571               pVpCtx->ExecutionState.InterruptShadow));
    2572         AssertMsg(!(pVpCtx->ExecutionState.AsUINT16 & ~UINT16_C(0x107f)),
    2573                   ("ExecutionState.AsUINT16=%#x\n", pVpCtx->ExecutionState.AsUINT16));
    2574 
    2575         /** @todo Someone at Microsoft please explain why the InstructionBytes fields
    2576          * are 16 bytes long, when 15 would've been sufficent and saved 3-7 bytes of
    2577          * alignment padding?  Intel max length is 15, so is this sSome ARM stuff?
    2578          * Aren't ARM
    2579          * instructions max 32-bit wide?  Confused. */
    2580         if (fExitInstr && pExitReason->IoPortAccess.InstructionByteCount > 0)
    2581             Log2(("Exit: + Instruction %.*Rhxs\n",
    2582                   pExitReason->IoPortAccess.InstructionByteCount, pExitReason->IoPortAccess.InstructionBytes));
    2583     }
    2584 }
    2585 
    2586 
    25871177/**
    25881178 * Logs the current CPU state.
    25891179 */
    2590 static void nemR3WinLogState(PVM pVM, PVMCPU pVCpu)
     1180NEM_TMPL_STATIC void nemHCWinLogState(PVM pVM, PVMCPU pVCpu)
    25911181{
    25921182    if (LogIs3Enabled())
    25931183    {
     1184# ifdef IN_RING3
    25941185        char szRegs[4096];
    25951186        DBGFR3RegPrintf(pVM->pUVM, pVCpu->idCpu, &szRegs[0], sizeof(szRegs),
     
    26251216                           szInstr, sizeof(szInstr), NULL);
    26261217        Log3(("%s%s\n", szRegs, szInstr));
    2627     }
    2628 }
    2629 
     1218# else
     1219        /** @todo stat logging in ring-0 */
     1220        RT_NOREF(pVM, pVCpu);
     1221# endif
     1222    }
     1223}
    26301224#endif /* LOG_ENABLED */
    26311225
     
    26401234 * @param   pExitCtx        The exit context.
    26411235 */
    2642 DECLINLINE(void) nemR3WinAdvanceGuestRipAndClearRF(PVMCPU pVCpu, PCPUMCTX pCtx, WHV_VP_EXIT_CONTEXT const *pExitCtx)
     1236DECLINLINE(void) nemHCWinAdvanceGuestRipAndClearRF(PVMCPU pVCpu, PCPUMCTX pCtx, WHV_VP_EXIT_CONTEXT const *pExitCtx)
    26431237{
    26441238    /* Advance the RIP. */
     
    26551249
    26561250
    2657 static VBOXSTRICTRC nemR3WinHandleHalt(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
     1251NEM_TMPL_STATIC VBOXSTRICTRC
     1252nemHCWinHandleHalt(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
    26581253{
    26591254    NOREF(pVM); NOREF(pVCpu); NOREF(pCtx);
    2660     LogFlow(("nemR3WinHandleHalt\n"));
     1255    LogFlow(("nemHCWinHandleHalt\n"));
    26611256    return VINF_EM_HALT;
    26621257}
    26631258
    26641259
    2665 static DECLCALLBACK(int) nemR3WinUnmapOnePageCallback(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, uint8_t *pu2NemState, void *pvUser)
     1260NEM_TMPL_STATIC DECLCALLBACK(int)
     1261nemHCWinUnmapOnePageCallback(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, uint8_t *pu2NemState, void *pvUser)
    26661262{
    26671263    RT_NOREF_PV(pvUser);
    26681264#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    2669     int rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhys);
     1265    int rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhys);
    26701266    AssertRC(rc);
    26711267    if (RT_SUCCESS(rc))
     
    26971293
    26981294/**
    2699  * State to pass between  nemR3WinHandleMemoryAccess and
    2700  * nemR3WinHandleMemoryAccessPageCheckerCallback.
     1295 * State to pass between nemHCWinHandleMemoryAccess / nemR3WinWHvHandleMemoryAccess
     1296 * and nemHCWinHandleMemoryAccessPageCheckerCallback.
    27011297 */
    2702 typedef struct NEMR3WINHMACPCCSTATE
     1298typedef struct NEMHCWINHMACPCCSTATE
    27031299{
    27041300    /** Input: Write access. */
     
    27081304    /** Output: Set it we should resume. */
    27091305    bool    fCanResume;
    2710 } NEMR3WINHMACPCCSTATE;
     1306} NEMHCWINHMACPCCSTATE;
    27111307
    27121308/**
    27131309 * @callback_method_impl{FNPGMPHYSNEMCHECKPAGE,
    27141310 *      Worker for nemR3WinHandleMemoryAccess; pvUser points to a
    2715  *      NEMR3WINHMACPCCSTATE structure. }
     1311 *      NEMHCWINHMACPCCSTATE structure. }
    27161312 */
    2717 static DECLCALLBACK(int) nemR3WinHandleMemoryAccessPageCheckerCallback(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys,
    2718                                                                       PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
    2719 {
    2720     NEMR3WINHMACPCCSTATE *pState = (NEMR3WINHMACPCCSTATE *)pvUser;
     1313NEM_TMPL_STATIC DECLCALLBACK(int)
     1314nemHCWinHandleMemoryAccessPageCheckerCallback(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
     1315{
     1316    NEMHCWINHMACPCCSTATE *pState = (NEMHCWINHMACPCCSTATE *)pvUser;
    27211317    pState->fDidSomething = false;
    27221318    pState->fCanResume    = false;
     
    27611357            if (pInfo->fNemProt == NEM_PAGE_PROT_NONE)
    27621358            {
    2763                 Log4(("nemR3WinHandleMemoryAccessPageCheckerCallback: %RGp - #1\n", GCPhys));
     1359                Log4(("nemHCWinHandleMemoryAccessPageCheckerCallback: %RGp - #1\n", GCPhys));
    27641360                return VINF_SUCCESS;
    27651361            }
     
    27691365                && !(pInfo->fNemProt & NEM_PAGE_PROT_WRITE))
    27701366            {
    2771                 Log4(("nemR3WinHandleMemoryAccessPageCheckerCallback: %RGp - #1w\n", GCPhys));
     1367                Log4(("nemHCWinHandleMemoryAccessPageCheckerCallback: %RGp - #1w\n", GCPhys));
    27721368                return VINF_SUCCESS;
    27731369            }
    27741370
    27751371            /* Map the page. */
    2776             rc = nemR3NativeSetPhysPage(pVM,
     1372            rc = nemHCNativeSetPhysPage(pVM,
    27771373                                        pVCpu,
    27781374                                        GCPhysSrc & ~(RTGCPHYS)X86_PAGE_OFFSET_MASK,
     
    27821378                                        true /*fBackingState*/);
    27831379            pInfo->u2NemState = u2State;
    2784             Log4(("nemR3WinHandleMemoryAccessPageCheckerCallback: %RGp - synced => %s + %Rrc\n",
     1380            Log4(("nemHCWinHandleMemoryAccessPageCheckerCallback: %RGp - synced => %s + %Rrc\n",
    27851381                  GCPhys, g_apszPageStates[u2State], rc));
    27861382            pState->fDidSomething = true;
     
    27921388                && (pInfo->fNemProt & (NEM_PAGE_PROT_READ | NEM_PAGE_PROT_EXECUTE)))
    27931389            {
    2794                 Log4(("nemR3WinHandleMemoryAccessPageCheckerCallback: %RGp - #2\n", GCPhys));
     1390                Log4(("nemHCWinHandleMemoryAccessPageCheckerCallback: %RGp - #2\n", GCPhys));
    27951391                return VINF_SUCCESS;
    27961392            }
     
    28021398                && pState->fWriteAccess)
    28031399            {
    2804                 rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhys,
     1400                rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhys,
    28051401                                              HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
    28061402                                              | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
     
    28291425            if (pInfo->fNemProt & NEM_PAGE_PROT_WRITE)
    28301426            {
    2831                 Log4(("nemR3WinHandleMemoryAccessPageCheckerCallback: %RGp - #3\n", GCPhys));
     1427                Log4(("nemHCWinHandleMemoryAccessPageCheckerCallback: %RGp - #3\n", GCPhys));
    28321428                return VINF_SUCCESS;
    28331429            }
     
    28461442     */
    28471443#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    2848     rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhys);
     1444    rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhys);
    28491445    AssertRC(rc);
    28501446    if (RT_SUCCESS(rc))
     
    28631459    }
    28641460#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    2865     LogRel(("nemR3WinHandleMemoryAccessPageCheckerCallback/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhys, rc));
     1461    LogRel(("nemHCWinHandleMemoryAccessPageCheckerCallback/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhys, rc));
    28661462    return rc;
    28671463#else
    2868     LogRel(("nemR3WinHandleMemoryAccessPageCheckerCallback/unmap: GCPhysDst=%RGp %s hrc=%Rhrc (%#x) Last=%#x/%u (cMappedPages=%u)\n",
     1464    LogRel(("nemHCWinHandleMemoryAccessPageCheckerCallback/unmap: GCPhysDst=%RGp %s hrc=%Rhrc (%#x) Last=%#x/%u (cMappedPages=%u)\n",
    28691465            GCPhys, g_apszPageStates[u2State], hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue(),
    28701466            pVM->nem.s.cMappedPages));
    28711467
    28721468    PGMPhysNemEnumPagesByState(pVM, pVCpu, NEM_WIN_PAGE_STATE_READABLE, nemR3WinUnmapOnePageCallback, NULL);
    2873     Log(("nemR3WinHandleMemoryAccessPageCheckerCallback: Unmapped all (cMappedPages=%u)\n", pVM->nem.s.cMappedPages));
     1469    Log(("nemHCWinHandleMemoryAccessPageCheckerCallback: Unmapped all (cMappedPages=%u)\n", pVM->nem.s.cMappedPages));
    28741470
    28751471    pState->fDidSomething = true;
     
    28811477
    28821478
    2883 /**
    2884  * Handles an memory access VMEXIT.
    2885  *
    2886  * This can be triggered by a number of things.
    2887  *
    2888  * @returns Strict VBox status code.
    2889  * @param   pVM             The cross context VM structure.
    2890  * @param   pVCpu           The cross context virtual CPU structure.
    2891  * @param   pCtx            The CPU context to update.
    2892  * @param   pMemCtx         The exit reason information.
    2893  */
    2894 static VBOXSTRICTRC nemR3WinHandleMemoryAccess(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_MEMORY_ACCESS_CONTEXT const *pMemCtx)
    2895 {
    2896     /*
    2897      * Ask PGM for information about the given GCPhys.  We need to check if we're
    2898      * out of sync first.
    2899      */
    2900     NEMR3WINHMACPCCSTATE State = { pMemCtx->AccessInfo.AccessType == WHvMemoryAccessWrite, false, false };
    2901     PGMPHYSNEMPAGEINFO   Info;
    2902     int rc = PGMPhysNemPageInfoChecker(pVM, pVCpu, pMemCtx->Gpa, State.fWriteAccess, &Info,
    2903                                        nemR3WinHandleMemoryAccessPageCheckerCallback, &State);
    2904     if (RT_SUCCESS(rc))
    2905     {
    2906         if (Info.fNemProt & (pMemCtx->AccessInfo.AccessType == WHvMemoryAccessWrite ? NEM_PAGE_PROT_WRITE : NEM_PAGE_PROT_READ))
    2907         {
    2908             if (State.fCanResume)
    2909             {
    2910                 Log4(("MemExit: %RGp (=>%RHp) %s fProt=%u%s%s%s; restarting (%s)\n",
    2911                       pMemCtx->Gpa, Info.HCPhys, g_apszPageStates[Info.u2NemState], Info.fNemProt,
    2912                       Info.fHasHandlers ? " handlers" : "", Info.fZeroPage    ? " zero-pg" : "",
    2913                       State.fDidSomething ? "" : " no-change", g_apszWHvMemAccesstypes[pMemCtx->AccessInfo.AccessType]));
    2914                 return VINF_SUCCESS;
    2915             }
    2916         }
    2917         Log4(("MemExit: %RGp (=>%RHp) %s fProt=%u%s%s%s; emulating (%s)\n",
    2918               pMemCtx->Gpa, Info.HCPhys, g_apszPageStates[Info.u2NemState], Info.fNemProt,
    2919               Info.fHasHandlers ? " handlers" : "", Info.fZeroPage    ? " zero-pg" : "",
    2920               State.fDidSomething ? "" : " no-change", g_apszWHvMemAccesstypes[pMemCtx->AccessInfo.AccessType]));
    2921     }
    2922     else
    2923         Log4(("MemExit: %RGp rc=%Rrc%s; emulating (%s)\n", pMemCtx->Gpa, rc,
    2924               State.fDidSomething ? " modified-backing" : "", g_apszWHvMemAccesstypes[pMemCtx->AccessInfo.AccessType]));
    2925 
    2926     /*
    2927      * Emulate the memory access, either access handler or special memory.
    2928      */
    2929     VBOXSTRICTRC rcStrict;
    2930     if (pMemCtx->InstructionByteCount > 0)
    2931         rcStrict = IEMExecOneWithPrefetchedByPC(pVCpu, CPUMCTX2CORE(pCtx), pMemCtx->VpContext.Rip,
    2932                                                 pMemCtx->InstructionBytes, pMemCtx->InstructionByteCount);
    2933     else
    2934         rcStrict = IEMExecOne(pVCpu);
    2935     /** @todo do we need to do anything wrt debugging here?   */
    2936     return rcStrict;
    2937 }
    2938 
    2939 
    2940 /**
    2941  * Handles an I/O port access VMEXIT.
    2942  *
    2943  * We ASSUME that the hypervisor has don't I/O port access control.
    2944  *
    2945  * @returns Strict VBox status code.
    2946  * @param   pVM             The cross context VM structure.
    2947  * @param   pVCpu           The cross context virtual CPU structure.
    2948  * @param   pCtx            The CPU context to update.
    2949  * @param   pIoPortCtx      The exit reason information.
    2950  */
    2951 static VBOXSTRICTRC nemR3WinHandleIoPortAccess(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx,
    2952                                                WHV_X64_IO_PORT_ACCESS_CONTEXT const *pIoPortCtx)
    2953 {
    2954     Assert(   pIoPortCtx->AccessInfo.AccessSize == 1
    2955            || pIoPortCtx->AccessInfo.AccessSize == 2
    2956            || pIoPortCtx->AccessInfo.AccessSize == 4);
    2957 
    2958     VBOXSTRICTRC rcStrict;
    2959     if (!pIoPortCtx->AccessInfo.StringOp)
    2960     {
    2961         /*
    2962          * Simple port I/O.
    2963          */
    2964         Assert(pCtx->rax == pIoPortCtx->Rax);
    2965 
    2966         static uint32_t const s_fAndMask[8] =
    2967         { UINT32_MAX, UINT32_C(0xff), UINT32_C(0xffff), UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX };
    2968         uint32_t const fAndMask = s_fAndMask[pIoPortCtx->AccessInfo.AccessSize];
    2969         if (pIoPortCtx->AccessInfo.IsWrite)
    2970         {
    2971             rcStrict = IOMIOPortWrite(pVM, pVCpu, pIoPortCtx->PortNumber, (uint32_t)pIoPortCtx->Rax & fAndMask,
    2972                                       pIoPortCtx->AccessInfo.AccessSize);
    2973             if (IOM_SUCCESS(rcStrict))
    2974                 nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pIoPortCtx->VpContext);
    2975         }
    2976         else
    2977         {
    2978             uint32_t uValue = 0;
    2979             rcStrict = IOMIOPortRead(pVM, pVCpu, pIoPortCtx->PortNumber, &uValue,
    2980                                      pIoPortCtx->AccessInfo.AccessSize);
    2981             if (IOM_SUCCESS(rcStrict))
    2982             {
    2983                 pCtx->eax = (pCtx->eax & ~fAndMask) | (uValue & fAndMask);
    2984                 nemR3WinAdvanceGuestRipAndClearRF(pVCpu, pCtx, &pIoPortCtx->VpContext);
    2985             }
    2986         }
    2987     }
    2988     else
    2989     {
    2990         /*
    2991          * String port I/O.
    2992          */
    2993         /** @todo Someone at Microsoft please explain how we can get the address mode
    2994          * from the IoPortAccess.VpContext.  CS.Attributes is only sufficient for
    2995          * getting the default mode, it can always be overridden by a prefix.   This
    2996          * forces us to interpret the instruction from opcodes, which is suboptimal.
    2997          * Both AMD-V and VT-x includes the address size in the exit info, at least on
    2998          * CPUs that are reasonably new. */
    2999         Assert(   pIoPortCtx->Ds.Base     == pCtx->ds.u64Base
    3000                && pIoPortCtx->Ds.Limit    == pCtx->ds.u32Limit
    3001                && pIoPortCtx->Ds.Selector == pCtx->ds.Sel);
    3002         Assert(   pIoPortCtx->Es.Base     == pCtx->es.u64Base
    3003                && pIoPortCtx->Es.Limit    == pCtx->es.u32Limit
    3004                && pIoPortCtx->Es.Selector == pCtx->es.Sel);
    3005         Assert(pIoPortCtx->Rdi == pCtx->rdi);
    3006         Assert(pIoPortCtx->Rsi == pCtx->rsi);
    3007         Assert(pIoPortCtx->Rcx == pCtx->rcx);
    3008         Assert(pIoPortCtx->Rcx == pCtx->rcx);
    3009 
    3010         rcStrict = IEMExecOne(pVCpu);
    3011     }
    3012     if (IOM_SUCCESS(rcStrict))
    3013     {
    3014         /*
    3015          * Do debug checks.
    3016          */
    3017         if (   pIoPortCtx->VpContext.ExecutionState.DebugActive /** @todo Microsoft: Does DebugActive this only reflext DR7? */
    3018             || (pIoPortCtx->VpContext.Rflags & X86_EFL_TF)
    3019             || DBGFBpIsHwIoArmed(pVM) )
    3020         {
    3021             /** @todo Debugging. */
    3022         }
    3023     }
    3024     return rcStrict;
    3025 }
    3026 
    3027 
    3028 static VBOXSTRICTRC nemR3WinHandleInterruptWindow(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    3029 {
    3030     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx); NOREF(pExitReason);
    3031     AssertLogRelFailedReturn(VERR_NOT_IMPLEMENTED);
    3032 }
    3033 
    3034 
    3035 static VBOXSTRICTRC nemR3WinHandleMsrAccess(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    3036 {
    3037     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx); NOREF(pExitReason);
    3038     AssertLogRelFailedReturn(VERR_NOT_IMPLEMENTED);
    3039 }
    3040 
    3041 
    3042 static VBOXSTRICTRC nemR3WinHandleCpuId(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    3043 {
    3044     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx); NOREF(pExitReason);
    3045     AssertLogRelFailedReturn(VERR_NOT_IMPLEMENTED);
    3046 }
    3047 
    3048 
    3049 static VBOXSTRICTRC nemR3WinHandleException(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    3050 {
    3051     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx); NOREF(pExitReason);
    3052     AssertLogRelFailedReturn(VERR_NOT_IMPLEMENTED);
    3053 }
    3054 
    3055 
    3056 static VBOXSTRICTRC nemR3WinHandleUD(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    3057 {
    3058     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx); NOREF(pExitReason);
    3059     AssertLogRelFailedReturn(VERR_NOT_IMPLEMENTED);
    3060 }
    3061 
    3062 
    3063 static VBOXSTRICTRC nemR3WinHandleTripleFault(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    3064 {
    3065     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx); NOREF(pExitReason);
    3066     AssertLogRelFailedReturn(VERR_NOT_IMPLEMENTED);
    3067 }
    3068 
    3069 
    3070 static VBOXSTRICTRC nemR3WinHandleInvalidState(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, WHV_RUN_VP_EXIT_CONTEXT const *pExitReason)
    3071 {
    3072     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx); NOREF(pExitReason);
    3073     AssertLogRelFailedReturn(VERR_NOT_IMPLEMENTED);
    3074 }
    3075 
    3076 
    3077 VBOXSTRICTRC nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu)
     1479#if 0 /* later */
     1480NEM_TMPL_STATIC nemHCWinRunGC(PVM pVM, PVMCPU pVCpu)
    30781481{
    30791482#ifdef LOG_ENABLED
     
    30991502         */
    31001503        PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
    3101         int rc2 = nemR3WinCopyStateToHyperV(pVM, pVCpu, pCtx);
     1504        int rc2 = nemHCWinCopyStateToHyperV(pVM, pVCpu, pCtx);
    31021505        AssertRCBreakStmt(rc2, rcStrict = rc2);
    31031506
     
    32681671    return rcStrict;
    32691672}
    3270 
    3271 
    3272 bool nemR3NativeCanExecuteGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)
    3273 {
    3274     NOREF(pVM); NOREF(pVCpu); NOREF(pCtx);
    3275     return true;
    3276 }
    3277 
    3278 
    3279 bool nemR3NativeSetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable)
    3280 {
    3281     NOREF(pVM); NOREF(pVCpu); NOREF(fEnable);
    3282     return false;
    3283 }
    3284 
    3285 
    3286 /**
    3287  * Forced flag notification call from VMEmt.h.
    3288  *
    3289  * This is only called when pVCpu is in the VMCPUSTATE_STARTED_EXEC_NEM state.
    3290  *
    3291  * @param   pVM             The cross context VM structure.
    3292  * @param   pVCpu           The cross context virtual CPU structure of the CPU
    3293  *                          to be notified.
    3294  * @param   fFlags          Notification flags, VMNOTIFYFF_FLAGS_XXX.
    3295  */
    3296 void nemR3NativeNotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags)
    3297 {
    3298 #ifdef NEM_WIN_USE_OUR_OWN_RUN_API
    3299     nemR3WinCancelRunVirtualProcessor(pVM, pVCpu);
    3300 #else
    3301     Log8(("nemR3NativeNotifyFF: canceling %u\n", pVCpu->idCpu));
    3302     HRESULT hrc = WHvCancelRunVirtualProcessor(pVM->nem.s.hPartition, pVCpu->idCpu, 0);
    3303     AssertMsg(SUCCEEDED(hrc), ("WHvCancelRunVirtualProcessor -> hrc=%Rhrc\n", hrc));
    3304     RT_NOREF_PV(hrc);
    3305 #endif
    3306     RT_NOREF_PV(fFlags);
    3307 }
    3308 
    3309 
    3310 DECLINLINE(int) nemR3NativeGCPhys2R3PtrReadOnly(PVM pVM, RTGCPHYS GCPhys, const void **ppv)
    3311 {
    3312     PGMPAGEMAPLOCK Lock;
    3313     int rc = PGMPhysGCPhys2CCPtrReadOnly(pVM, GCPhys, ppv, &Lock);
    3314     if (RT_SUCCESS(rc))
    3315         PGMPhysReleasePageMappingLock(pVM, &Lock);
    3316     return rc;
    3317 }
    3318 
    3319 
    3320 DECLINLINE(int) nemR3NativeGCPhys2R3PtrWriteable(PVM pVM, RTGCPHYS GCPhys, void **ppv)
    3321 {
    3322     PGMPAGEMAPLOCK Lock;
    3323     int rc = PGMPhysGCPhys2CCPtr(pVM, GCPhys, ppv, &Lock);
    3324     if (RT_SUCCESS(rc))
    3325         PGMPhysReleasePageMappingLock(pVM, &Lock);
    3326     return rc;
    3327 }
    3328 
    3329 
    3330 int nemR3NativeNotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb)
    3331 {
    3332     Log5(("nemR3NativeNotifyPhysRamRegister: %RGp LB %RGp\n", GCPhys, cb));
    3333     NOREF(pVM); NOREF(GCPhys); NOREF(cb);
    3334     return VINF_SUCCESS;
    3335 }
    3336 
    3337 
    3338 int nemR3NativeNotifyPhysMmioExMap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, void *pvMmio2)
    3339 {
    3340     Log5(("nemR3NativeNotifyPhysMmioExMap: %RGp LB %RGp fFlags=%#x pvMmio2=%p\n", GCPhys, cb, fFlags, pvMmio2));
    3341     NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags); NOREF(pvMmio2);
    3342     return VINF_SUCCESS;
    3343 }
    3344 
    3345 
    3346 int nemR3NativeNotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
    3347 {
    3348     Log5(("nemR3NativeNotifyPhysMmioExUnmap: %RGp LB %RGp fFlags=%#x\n", GCPhys, cb, fFlags));
    3349     NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
    3350     return VINF_SUCCESS;
    3351 }
    3352 
    3353 
    3354 /**
    3355  * Called early during ROM registration, right after the pages have been
    3356  * allocated and the RAM range updated.
    3357  *
    3358  * This will be succeeded by a number of NEMHCNotifyPhysPageProtChanged() calls
    3359  * and finally a NEMR3NotifyPhysRomRegisterEarly().
    3360  *
    3361  * @returns VBox status code
    3362  * @param   pVM             The cross context VM structure.
    3363  * @param   GCPhys          The ROM address (page aligned).
    3364  * @param   cb              The size (page aligned).
    3365  * @param   fFlags          NEM_NOTIFY_PHYS_ROM_F_XXX.
    3366  */
    3367 int nemR3NativeNotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
    3368 {
    3369     Log5(("nemR3NativeNotifyPhysRomRegisterEarly: %RGp LB %RGp fFlags=%#x\n", GCPhys, cb, fFlags));
    3370 #if 0 /* Let's not do this after all.  We'll protection change notifications for each page and if not we'll map them lazily. */
    3371     RTGCPHYS const cPages = cb >> X86_PAGE_SHIFT;
    3372     for (RTGCPHYS iPage = 0; iPage < cPages; iPage++, GCPhys += X86_PAGE_SIZE)
    3373     {
    3374         const void *pvPage;
    3375         int rc = nemR3NativeGCPhys2R3PtrReadOnly(pVM, GCPhys, &pvPage);
    3376         if (RT_SUCCESS(rc))
    3377         {
    3378             HRESULT hrc = WHvMapGpaRange(pVM->nem.s.hPartition, (void *)pvPage, GCPhys, X86_PAGE_SIZE,
    3379                                          WHvMapGpaRangeFlagRead | WHvMapGpaRangeFlagExecute);
    3380             if (SUCCEEDED(hrc))
    3381             { /* likely */ }
    3382             else
    3383             {
    3384                 LogRel(("nemR3NativeNotifyPhysRomRegisterEarly: GCPhys=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
    3385                         GCPhys, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
    3386                 return VERR_NEM_INIT_FAILED;
    3387             }
    3388         }
    3389         else
    3390         {
    3391             LogRel(("nemR3NativeNotifyPhysRomRegisterEarly: GCPhys=%RGp rc=%Rrc\n", GCPhys, rc));
    3392             return rc;
    3393         }
    3394     }
    3395 #else
    3396     NOREF(pVM); NOREF(GCPhys); NOREF(cb);
    3397 #endif
    3398     RT_NOREF_PV(fFlags);
    3399     return VINF_SUCCESS;
    3400 }
    3401 
    3402 
    3403 /**
    3404  * Called after the ROM range has been fully completed.
    3405  *
    3406  * This will be preceeded by a NEMR3NotifyPhysRomRegisterEarly() call as well a
    3407  * number of NEMHCNotifyPhysPageProtChanged calls.
    3408  *
    3409  * @returns VBox status code
    3410  * @param   pVM             The cross context VM structure.
    3411  * @param   GCPhys          The ROM address (page aligned).
    3412  * @param   cb              The size (page aligned).
    3413  * @param   fFlags          NEM_NOTIFY_PHYS_ROM_F_XXX.
    3414  */
    3415 int nemR3NativeNotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags)
    3416 {
    3417     Log5(("nemR3NativeNotifyPhysRomRegisterLate: %RGp LB %RGp fFlags=%#x\n", GCPhys, cb, fFlags));
    3418     NOREF(pVM); NOREF(GCPhys); NOREF(cb); NOREF(fFlags);
    3419     return VINF_SUCCESS;
    3420 }
     1673#endif /* later */
     1674
     1675
     1676#endif /* IN_RING0 */
    34211677
    34221678
     
    34241680 * @callback_method_impl{FNPGMPHYSNEMCHECKPAGE}
    34251681 */
    3426 static DECLCALLBACK(int) nemR3WinUnsetForA20CheckerCallback(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys,
    3427                                                             PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
     1682NEM_TMPL_STATIC DECLCALLBACK(int) nemHCWinUnsetForA20CheckerCallback(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys,
     1683                                                                     PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)
    34281684{
    34291685    /* We'll just unmap the memory. */
     
    34311687    {
    34321688#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    3433         int rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhys);
     1689        int rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhys);
    34341690        AssertRC(rc);
    34351691        if (RT_SUCCESS(rc))
     
    34461702        {
    34471703#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    3448             LogRel(("nemR3WinUnsetForA20CheckerCallback/unmap: GCPhys=%RGp rc=%Rrc\n", GCPhys, rc));
     1704            LogRel(("nemHCWinUnsetForA20CheckerCallback/unmap: GCPhys=%RGp rc=%Rrc\n", GCPhys, rc));
    34491705            return rc;
    34501706#else
    3451             LogRel(("nemR3WinUnsetForA20CheckerCallback/unmap: GCPhys=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
     1707            LogRel(("nemHCWinUnsetForA20CheckerCallback/unmap: GCPhys=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
    34521708                    GCPhys, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
    34531709            return VERR_INTERNAL_ERROR_2;
     
    34681724 * @param   GCPhys          The page to unmap.
    34691725 */
    3470 static int nemR3WinUnmapPageForA20Gate(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
     1726NEM_TMPL_STATIC int nemHCWinUnmapPageForA20Gate(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
    34711727{
    34721728    PGMPHYSNEMPAGEINFO Info;
    34731729    return PGMPhysNemPageInfoChecker(pVM, pVCpu, GCPhys, false /*fMakeWritable*/, &Info,
    3474                                      nemR3WinUnsetForA20CheckerCallback, NULL);
    3475 }
    3476 
    3477 
    3478 /**
    3479  * Called when the A20 state changes.
    3480  *
    3481  * Hyper-V doesn't seem to offer a simple way of implementing the A20 line
    3482  * features of PCs.  So, we do a very minimal emulation of the HMA to make DOS
    3483  * happy.
    3484  *
    3485  * @param   pVCpu           The CPU the A20 state changed on.
    3486  * @param   fEnabled        Whether it was enabled (true) or disabled.
    3487  */
    3488 void nemR3NativeNotifySetA20(PVMCPU pVCpu, bool fEnabled)
    3489 {
    3490     Log(("nemR3NativeNotifySetA20: fEnabled=%RTbool\n", fEnabled));
    3491     PVM pVM = pVCpu->CTX_SUFF(pVM);
    3492     if (!pVM->nem.s.fA20Fixed)
    3493     {
    3494         pVM->nem.s.fA20Enabled = fEnabled;
    3495         for (RTGCPHYS GCPhys = _1M; GCPhys < _1M + _64K; GCPhys += X86_PAGE_SIZE)
    3496             nemR3WinUnmapPageForA20Gate(pVM, pVCpu, GCPhys);
    3497     }
    3498 }
    3499 
    3500 
    3501 void nemR3NativeNotifyHandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb)
    3502 {
    3503     Log5(("nemR3NativeNotifyHandlerPhysicalRegister: %RGp LB %RGp enmKind=%d\n", GCPhys, cb, enmKind));
     1730                                     nemHCWinUnsetForA20CheckerCallback, NULL);
     1731}
     1732
     1733
     1734void nemHCNativeNotifyHandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb)
     1735{
     1736    Log5(("nemHCNativeNotifyHandlerPhysicalRegister: %RGp LB %RGp enmKind=%d\n", GCPhys, cb, enmKind));
    35041737    NOREF(pVM); NOREF(enmKind); NOREF(GCPhys); NOREF(cb);
    35051738}
    35061739
    35071740
    3508 void nemR3NativeNotifyHandlerPhysicalDeregister(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb,
     1741void nemHCNativeNotifyHandlerPhysicalDeregister(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb,
    35091742                                                int fRestoreAsRAM, bool fRestoreAsRAM2)
    35101743{
    3511     Log5(("nemR3NativeNotifyHandlerPhysicalDeregister: %RGp LB %RGp enmKind=%d fRestoreAsRAM=%d fRestoreAsRAM2=%d\n",
     1744    Log5(("nemHCNativeNotifyHandlerPhysicalDeregister: %RGp LB %RGp enmKind=%d fRestoreAsRAM=%d fRestoreAsRAM2=%d\n",
    35121745          GCPhys, cb, enmKind, fRestoreAsRAM, fRestoreAsRAM2));
    35131746    NOREF(pVM); NOREF(enmKind); NOREF(GCPhys); NOREF(cb); NOREF(fRestoreAsRAM); NOREF(fRestoreAsRAM2);
     
    35151748
    35161749
    3517 void nemR3NativeNotifyHandlerPhysicalModify(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
     1750void nemHCNativeNotifyHandlerPhysicalModify(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
    35181751                                            RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM)
    35191752{
    3520     Log5(("nemR3NativeNotifyHandlerPhysicalModify: %RGp LB %RGp -> %RGp enmKind=%d fRestoreAsRAM=%d\n",
     1753    Log5(("nemHCNativeNotifyHandlerPhysicalModify: %RGp LB %RGp -> %RGp enmKind=%d fRestoreAsRAM=%d\n",
    35211754          GCPhysOld, cb, GCPhysNew, enmKind, fRestoreAsRAM));
    35221755    NOREF(pVM); NOREF(enmKind); NOREF(GCPhysOld); NOREF(GCPhysNew); NOREF(cb); NOREF(fRestoreAsRAM);
     
    35421775 * @thread  EMT(pVCpu)
    35431776 */
    3544 static int nemR3NativeSetPhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst, uint32_t fPageProt,
    3545                                   uint8_t *pu2State, bool fBackingChanged)
     1777NEM_TMPL_STATIC int nemHCNativeSetPhysPage(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhysSrc, RTGCPHYS GCPhysDst,
     1778                                           uint32_t fPageProt, uint8_t *pu2State, bool fBackingChanged)
    35461779{
    35471780#ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
     
    35581791        if (u2OldState > NEM_WIN_PAGE_STATE_UNMAPPED)
    35591792        {
    3560             rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
     1793            rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
    35611794            if (RT_SUCCESS(rc))
    35621795            {
     
    35661799            }
    35671800            else
    3568                 AssertLogRelMsgFailed(("nemR3NativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     1801                AssertLogRelMsgFailed(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
    35691802        }
    35701803        else
     
    35751808        if (u2OldState != NEM_WIN_PAGE_STATE_WRITABLE || fBackingChanged)
    35761809        {
    3577             rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
     1810            rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
    35781811                                            HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
    35791812                                          | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
     
    35871820            }
    35881821            else
    3589                 AssertLogRelMsgFailed(("nemR3NativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     1822                AssertLogRelMsgFailed(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
    35901823        }
    35911824        else
     
    35961829        if (u2OldState != NEM_WIN_PAGE_STATE_READABLE || fBackingChanged)
    35971830        {
    3598             rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
     1831            rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
    35991832                                          HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
    36001833            if (RT_SUCCESS(rc))
     
    36071840            }
    36081841            else
    3609                 AssertLogRelMsgFailed(("nemR3NativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     1842                AssertLogRelMsgFailed(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
    36101843        }
    36111844        else
     
    36301863        {
    36311864# ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    3632             int rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
     1865            int rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
    36331866            AssertRC(rc);
    36341867            if (RT_SUCCESS(rc))
     
    36451878            else
    36461879            {
    3647                 LogRel(("nemR3NativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     1880                LogRel(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
    36481881                return rc;
    36491882            }
     
    36631896            else
    36641897            {
    3665                 LogRel(("nemR3NativeSetPhysPage/unmap: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
     1898                LogRel(("nemHCNativeSetPhysPage/unmap: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
    36661899                        GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
    36671900                return VERR_NEM_INIT_FAILED;
     
    36771910    {
    36781911# ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    3679         int rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
     1912        int rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
    36801913                                            HV_MAP_GPA_READABLE   | HV_MAP_GPA_WRITABLE
    36811914                                          | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
     
    36891922            return VINF_SUCCESS;
    36901923        }
    3691         LogRel(("nemR3NativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     1924        LogRel(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
    36921925        return rc;
    36931926# else
     
    37061939                return VINF_SUCCESS;
    37071940            }
    3708             LogRel(("nemR3NativeSetPhysPage/writable: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
     1941            LogRel(("nemHCNativeSetPhysPage/writable: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
    37091942                    GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
    37101943            return VERR_NEM_INIT_FAILED;
    37111944        }
    3712         LogRel(("nemR3NativeSetPhysPage/writable: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
     1945        LogRel(("nemHCNativeSetPhysPage/writable: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
    37131946        return rc;
    37141947# endif
     
    37181951    {
    37191952# ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
    3720         int rc = nemR3WinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
     1953        int rc = nemHCWinHypercallMapPage(pVM, pVCpu, GCPhysSrc, GCPhysDst,
    37211954                                          HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_EXECUTABLE_AGAIN);
    37221955        AssertRC(rc);
     
    37291962            return VINF_SUCCESS;
    37301963        }
    3731         LogRel(("nemR3NativeSetPhysPage/readonly: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     1964        LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
    37321965        return rc;
    37331966# else
     
    37461979                return VINF_SUCCESS;
    37471980            }
    3748             LogRel(("nemR3NativeSetPhysPage/readonly: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
     1981            LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysDst=%RGp hrc=%Rhrc (%#x) Last=%#x/%u\n",
    37491982                    GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
    37501983            return VERR_NEM_INIT_FAILED;
    37511984        }
    3752         LogRel(("nemR3NativeSetPhysPage/readonly: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
     1985        LogRel(("nemHCNativeSetPhysPage/readonly: GCPhysSrc=%RGp rc=%Rrc\n", GCPhysSrc, rc));
    37531986        return rc;
    37541987# endif
     
    37621995
    37631996
    3764 static int nemR3JustUnmapPageFromHyperV(PVM pVM, RTGCPHYS GCPhysDst, uint8_t *pu2State)
     1997NEM_TMPL_STATIC int nemHCJustUnmapPageFromHyperV(PVM pVM, RTGCPHYS GCPhysDst, uint8_t *pu2State)
    37651998{
    37661999    if (*pu2State <= NEM_WIN_PAGE_STATE_UNMAPPED)
    37672000    {
    3768         Log5(("nemR3JustUnmapPageFromHyperV: %RGp == unmapped\n", GCPhysDst));
     2001        Log5(("nemHCJustUnmapPageFromHyperV: %RGp == unmapped\n", GCPhysDst));
    37692002        *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
    37702003        return VINF_SUCCESS;
    37712004    }
    37722005
    3773 #ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
     2006#if defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES) || defined(IN_RING0)
    37742007    PVMCPU pVCpu = VMMGetCpu(pVM);
    3775     int rc = nemR3WinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
     2008    int rc = nemHCWinHypercallUnmapPage(pVM, pVCpu, GCPhysDst);
    37762009    AssertRC(rc);
    37772010    if (RT_SUCCESS(rc))
     
    37822015        return VINF_SUCCESS;
    37832016    }
    3784     LogRel(("nemR3JustUnmapPageFromHyperV/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
     2017    LogRel(("nemHCJustUnmapPageFromHyperV/unmap: GCPhysDst=%RGp rc=%Rrc\n", GCPhysDst, rc));
    37852018    return rc;
    37862019#else
     
    37902023        uint32_t cMappedPages = ASMAtomicDecU32(&pVM->nem.s.cMappedPages); NOREF(cMappedPages);
    37912024        *pu2State = NEM_WIN_PAGE_STATE_UNMAPPED;
    3792         Log5(("nemR3JustUnmapPageFromHyperV: %RGp => unmapped (total %u)\n", GCPhysDst, cMappedPages));
     2025        Log5(("nemHCJustUnmapPageFromHyperV: %RGp => unmapped (total %u)\n", GCPhysDst, cMappedPages));
    37932026        return VINF_SUCCESS;
    37942027    }
    3795     LogRel(("nemR3JustUnmapPageFromHyperV(%RGp): failed! hrc=%Rhrc (%#x) Last=%#x/%u\n",
     2028    LogRel(("nemHCJustUnmapPageFromHyperV(%RGp): failed! hrc=%Rhrc (%#x) Last=%#x/%u\n",
    37962029            GCPhysDst, hrc, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()));
    37972030    return VERR_INTERNAL_ERROR_3;
     
    38002033
    38012034
    3802 int nemR3NativeNotifyPhysPageAllocated(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
     2035int nemHCNativeNotifyPhysPageAllocated(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
    38032036                                       PGMPAGETYPE enmType, uint8_t *pu2State)
    38042037{
    3805     Log5(("nemR3NativeNotifyPhysPageAllocated: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
     2038    Log5(("nemHCNativeNotifyPhysPageAllocated: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
    38062039          GCPhys, HCPhys, fPageProt, enmType, *pu2State));
    38072040    RT_NOREF_PV(HCPhys); RT_NOREF_PV(enmType);
    38082041
    38092042    int rc;
    3810 #ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
     2043#if defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES) || defined(IN_RING0)
    38112044    PVMCPU pVCpu = VMMGetCpu(pVM);
    38122045    if (   pVM->nem.s.fA20Enabled
    38132046        || !NEM_WIN_IS_RELEVANT_TO_A20(GCPhys))
    3814         rc = nemR3NativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
     2047        rc = nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
    38152048    else
    38162049    {
    38172050        /* To keep effort at a minimum, we unmap the HMA page alias and resync it lazily when needed. */
    3818         rc = nemR3WinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
     2051        rc = nemHCWinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
    38192052        if (!NEM_WIN_IS_SUBJECT_TO_A20(GCPhys) && RT_SUCCESS(rc))
    3820             rc = nemR3NativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
     2053            rc = nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
    38212054
    38222055    }
     
    38352068
    38362069
    3837 void nemR3NativeNotifyPhysPageProtChanged(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
     2070void nemHCNativeNotifyPhysPageProtChanged(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
    38382071                                          PGMPAGETYPE enmType, uint8_t *pu2State)
    38392072{
    3840     Log5(("nemR3NativeNotifyPhysPageProtChanged: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
     2073    Log5(("nemHCNativeNotifyPhysPageProtChanged: %RGp HCPhys=%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
    38412074          GCPhys, HCPhys, fPageProt, enmType, *pu2State));
    38422075    RT_NOREF_PV(HCPhys); RT_NOREF_PV(enmType);
    38432076
    3844 #ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
     2077#if defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES) || defined(IN_RING0)
    38452078    PVMCPU pVCpu = VMMGetCpu(pVM);
    38462079    if (   pVM->nem.s.fA20Enabled
    38472080        || !NEM_WIN_IS_RELEVANT_TO_A20(GCPhys))
    3848         nemR3NativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, false /*fBackingChanged*/);
     2081        nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, false /*fBackingChanged*/);
    38492082    else
    38502083    {
    38512084        /* To keep effort at a minimum, we unmap the HMA page alias and resync it lazily when needed. */
    3852         nemR3WinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
     2085        nemHCWinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
    38532086        if (!NEM_WIN_IS_SUBJECT_TO_A20(GCPhys))
    3854             nemR3NativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, false /*fBackingChanged*/);
     2087            nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, false /*fBackingChanged*/);
    38552088    }
    38562089#else
     
    38662099
    38672100
    3868 void nemR3NativeNotifyPhysPageChanged(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew,
    3869                                       uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State)
    3870 {
    3871     Log5(("nemR3NativeNotifyPhysPageProtChanged: %RGp HCPhys=%RHp->%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
     2101void nemHCNativeNotifyPhysPageChanged(PVM pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew,
     2102                                     uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State)
     2103{
     2104    Log5(("nemHCNativeNotifyPhysPageChanged: %RGp HCPhys=%RHp->%RHp fPageProt=%#x enmType=%d *pu2State=%d\n",
    38722105          GCPhys, HCPhysPrev, HCPhysNew, fPageProt, enmType, *pu2State));
    38732106    RT_NOREF_PV(HCPhysPrev); RT_NOREF_PV(HCPhysNew); RT_NOREF_PV(enmType);
    38742107
    3875 #ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES
     2108#if defined(NEM_WIN_USE_HYPERCALLS_FOR_PAGES) || defined(IN_RING0)
    38762109    PVMCPU pVCpu = VMMGetCpu(pVM);
    38772110    if (   pVM->nem.s.fA20Enabled
    38782111        || !NEM_WIN_IS_RELEVANT_TO_A20(GCPhys))
    3879         nemR3NativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
     2112        nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
    38802113    else
    38812114    {
    38822115        /* To keep effort at a minimum, we unmap the HMA page alias and resync it lazily when needed. */
    3883         nemR3WinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
     2116        nemHCWinUnmapPageForA20Gate(pVM, pVCpu, GCPhys | RT_BIT_32(20));
    38842117        if (!NEM_WIN_IS_SUBJECT_TO_A20(GCPhys))
    3885             nemR3NativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
     2118            nemHCNativeSetPhysPage(pVM, pVCpu, GCPhys, GCPhys, fPageProt, pu2State, true /*fBackingChanged*/);
    38862119    }
    38872120#else
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