Changeset 71136 in vbox
- Timestamp:
- Feb 27, 2018 1:17:36 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/sup.h
r70918 r71136 1927 1927 SUPR0DECL(void) SUPR0BadContext(PSUPDRVSESSION pSession, const char *pszFile, uint32_t uLine, const char *pszExpr); 1928 1928 1929 /** Context structure returned by SUPR0IoCtlSetup for use with 1930 * SUPR0IoCtlPerform and cleaned up by SUPR0IoCtlCleanup. */ 1931 typedef struct SUPR0IOCTLCTX *PSUPR0IOCTLCTX; 1932 1933 /** 1934 * Sets up a I/O control context for the given handle. 1935 * 1936 * @returns VBox status code. 1937 * @param pSession The support driver session. 1938 * @param hHandle The handle. 1939 * @param fFlags Flag, MBZ. 1940 * @param ppCtx Where the context is returned. 1941 */ 1942 SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx); 1943 1944 /** 1945 * Cleans up the I/O control context when done. 1946 * 1947 * This won't close the handle passed to SUPR0IoCtlSetupForHandle. 1948 * 1949 * @returns VBox status code. 1950 * @param pCtx The I/O control context to cleanup. 1951 */ 1952 SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx); 1953 1954 /** 1955 * Performs an I/O control operation. 1956 * 1957 * @returns VBox status code. 1958 * @param pCtx The I/O control context returned by 1959 * SUPR0IoCtlSetupForHandle. 1960 * @param uFunction The I/O control function to perform. 1961 * @param pvInput Pointer to input buffer (ring-0). 1962 * @param pvInputUser Ring-3 pointer corresponding to @a pvInput. 1963 * @param cbInput The amount of input. If zero, both input pointers 1964 * are expected to be NULL. 1965 * @param pvOutput Pointer to output buffer (ring-0). 1966 * @param pvOutputUser Ring-3 pointer corresponding to @a pvInput. 1967 * @param cbOutput The amount of input. If zero, both input pointers 1968 * are expected to be NULL. 1969 * @param piNativeRc Where to return the native return code. When 1970 * specified the VBox status code will typically be 1971 * VINF_SUCCESS and the caller have to consult this for 1972 * the actual result of the operation. (This saves 1973 * pointless status code conversion.) Optional. 1974 * 1975 * @note On unix systems where there is only one set of buffers possible, 1976 * pass the same pointers as input and output. 1977 */ 1978 SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction, 1979 void *pvInput, RTR3PTR pvInputUser, size_t cbInput, 1980 void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput, 1981 int32_t *piNativeRc); 1982 1929 1983 /** 1930 1984 * Writes to the debugger and/or kernel log. -
trunk/include/VBox/vmm/gvm.h
r71075 r71136 125 125 struct NEMR0PERVM s; 126 126 # endif 127 uint8_t padding[ 64];127 uint8_t padding[128]; 128 128 } nem; 129 129 #endif -
trunk/include/VBox/vmm/nem.h
r71087 r71136 84 84 * @{ */ 85 85 VMMR0_INT_DECL(int) NEMR0InitVM(PGVM pGVM, PVM pVM); 86 VMMR0_INT_DECL(int) NEMR0InitVMPart2(PGVM pGVM, PVM pVM); 86 87 VMMR0_INT_DECL(void) NEMR0CleanupVM(PGVM pGVM); 87 88 VMMR0_INT_DECL(int) NEMR0MapPages(PGVM pGVM, PVM pVM, VMCPUID idCpu); -
trunk/include/VBox/vmm/vmm.h
r71087 r71136 432 432 /** Call NEMR0InitVM() (host specific). */ 433 433 VMMR0_DO_NEM_INIT_VM = 576, 434 /** Call NEMR0InitVMPart2() (host specific). */ 435 VMMR0_DO_NEM_INIT_VM_PART_2, 434 436 /** Call NEMR0MapPages() (host specific). */ 435 437 VMMR0_DO_NEM_MAP_PAGES, -
trunk/include/iprt/nt/vid.h
r71131 r71136 108 108 typedef VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT const *PCVID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT; 109 109 110 111 RT_C_DECLS_BEGIN112 113 /** Calling convention. */114 #ifndef WINAPI115 # define VIDAPI __stdcall116 #else117 # define VIDAPI WINAPI118 #endif119 120 /** Partition handle. */121 #ifndef WINAPI122 typedef void *VID_PARTITION_HANDLE;123 #else124 typedef HANDLE VID_PARTITION_HANDLE;125 #endif126 127 /**128 * Gets the partition ID.129 *130 * The partition ID is the numeric identifier used when making hypercalls to the131 * hypervisor.132 */133 DECLIMPORT(BOOL) VIDAPI VidGetHvPartitionId(VID_PARTITION_HANDLE hPartition, HV_PARTITION_ID *pidPartition);134 135 /**136 * Starts asynchronous execution of a virtual CPU.137 */138 DECLIMPORT(BOOL) VIDAPI VidStartVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu);139 140 /**141 * Stops the asynchronous execution of a virtual CPU.142 *143 * @retval ERROR_VID_STOP_PENDING if busy with intercept, check messages.144 */145 DECLIMPORT(BOOL) VIDAPI VidStopVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu);146 147 /**148 * WHvCreateVirtualProcessor boils down to a call to VidMessageSlotMap and149 * some internal WinHvPlatform state fiddling.150 *151 * Looks like it maps memory and returns the pointer to it.152 * VidMessageSlotHandleAndGetNext is later used to wait for the next message and153 * put (??) it into that memory mapping.154 *155 * @returns Success indicator (details in LastStatusValue and LastErrorValue).156 *157 * @param hPartition The partition handle.158 * @param pOutput Where to return the pointer to the message memory159 * mapping. The CPU index is also returned here.160 * @param iCpu The CPU to wait-and-get messages for.161 */162 DECLIMPORT(BOOL) VIDAPI VidMessageSlotMap(VID_PARTITION_HANDLE hPartition, PVID_MAPPED_MESSAGE_SLOT pOutput, HV_VP_INDEX iCpu);163 164 /**165 * This is used by WHvRunVirtualProcessor to wait for the next exit msg.166 *167 * The message appears in the memory mapping returned by VidMessageSlotMap.168 *169 * @returns Success indicator (details only in LastErrorValue - LastStatusValue170 * is not set).171 * @retval STATUS_TIMEOUT for STATUS_TIMEOUT as well as STATUS_USER_APC and172 * STATUS_ALERTED.173 *174 * @param hPartition The partition handle.175 * @param iCpu The CPU to wait-and-get messages for.176 * @param fFlags Flags. At least one of the two flags must be set:177 * - VID_MSHAGN_F_GET_NEXT_MESSAGE (bit 0)178 * - VID_MSHAGN_F_HANDLE_MESSAGE (bit 1)179 * @param cMillies The timeout, presumably in milliseconds.180 *181 * @todo Would be awfully nice if someone at Microsoft could hit at the182 * flags here.183 * @note184 */185 DECLIMPORT(BOOL) VIDAPI VidMessageSlotHandleAndGetNext(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu,186 uint32_t fFlags, uint32_t cMillies);187 110 /** @name VID_MSHAGN_F_GET_XXX - Flags for VidMessageSlotHandleAndGetNext 188 111 * @{ */ … … 196 119 /** @} */ 197 120 121 122 #ifdef IN_RING3 123 RT_C_DECLS_BEGIN 124 125 /** Calling convention. */ 126 #ifndef WINAPI 127 # define VIDAPI __stdcall 128 #else 129 # define VIDAPI WINAPI 130 #endif 131 132 /** Partition handle. */ 133 #ifndef WINAPI 134 typedef void *VID_PARTITION_HANDLE; 135 #else 136 typedef HANDLE VID_PARTITION_HANDLE; 137 #endif 138 139 /** 140 * Gets the partition ID. 141 * 142 * The partition ID is the numeric identifier used when making hypercalls to the 143 * hypervisor. 144 */ 145 DECLIMPORT(BOOL) VIDAPI VidGetHvPartitionId(VID_PARTITION_HANDLE hPartition, HV_PARTITION_ID *pidPartition); 146 147 /** 148 * Starts asynchronous execution of a virtual CPU. 149 */ 150 DECLIMPORT(BOOL) VIDAPI VidStartVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu); 151 152 /** 153 * Stops the asynchronous execution of a virtual CPU. 154 * 155 * @retval ERROR_VID_STOP_PENDING if busy with intercept, check messages. 156 */ 157 DECLIMPORT(BOOL) VIDAPI VidStopVirtualProcessor(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu); 158 159 /** 160 * WHvCreateVirtualProcessor boils down to a call to VidMessageSlotMap and 161 * some internal WinHvPlatform state fiddling. 162 * 163 * Looks like it maps memory and returns the pointer to it. 164 * VidMessageSlotHandleAndGetNext is later used to wait for the next message and 165 * put (??) it into that memory mapping. 166 * 167 * @returns Success indicator (details in LastStatusValue and LastErrorValue). 168 * 169 * @param hPartition The partition handle. 170 * @param pOutput Where to return the pointer to the message memory 171 * mapping. The CPU index is also returned here. 172 * @param iCpu The CPU to wait-and-get messages for. 173 */ 174 DECLIMPORT(BOOL) VIDAPI VidMessageSlotMap(VID_PARTITION_HANDLE hPartition, PVID_MAPPED_MESSAGE_SLOT pOutput, HV_VP_INDEX iCpu); 175 176 /** 177 * This is used by WHvRunVirtualProcessor to wait for the next exit msg. 178 * 179 * The message appears in the memory mapping returned by VidMessageSlotMap. 180 * 181 * @returns Success indicator (details only in LastErrorValue - LastStatusValue 182 * is not set). 183 * @retval STATUS_TIMEOUT for STATUS_TIMEOUT as well as STATUS_USER_APC and 184 * STATUS_ALERTED. 185 * 186 * @param hPartition The partition handle. 187 * @param iCpu The CPU to wait-and-get messages for. 188 * @param fFlags Flags. At least one of the two flags must be set: 189 * - VID_MSHAGN_F_GET_NEXT_MESSAGE (bit 0) 190 * - VID_MSHAGN_F_HANDLE_MESSAGE (bit 1) 191 * @param cMillies The timeout, presumably in milliseconds. 192 * 193 * @todo Would be awfully nice if someone at Microsoft could hit at the 194 * flags here. 195 * @note 196 */ 197 DECLIMPORT(BOOL) VIDAPI VidMessageSlotHandleAndGetNext(VID_PARTITION_HANDLE hPartition, HV_VP_INDEX iCpu, 198 uint32_t fFlags, uint32_t cMillies); 198 199 /** 199 200 * Gets the processor running status. … … 219 220 220 221 RT_C_DECLS_END 222 #endif /* IN_RING3 */ 221 223 222 224 #endif -
trunk/src/VBox/HostDrivers/Support/SUPDrv.cpp
r71075 r71136 231 231 { "SUPR0TracerUmodProbeFire", (void *)(uintptr_t)SUPR0TracerUmodProbeFire }, 232 232 { "SUPR0UnlockMem", (void *)(uintptr_t)SUPR0UnlockMem }, 233 #ifdef RT_OS_WINDOWS 234 { "SUPR0IoCtlSetupForHandle", (void *)(uintptr_t)SUPR0IoCtlSetupForHandle }, /* only-windows */ 235 { "SUPR0IoCtlPerform", (void *)(uintptr_t)SUPR0IoCtlPerform }, /* only-windows */ 236 { "SUPR0IoCtlCleanup", (void *)(uintptr_t)SUPR0IoCtlCleanup }, /* only-windows */ 237 #endif 233 238 { "SUPSemEventClose", (void *)(uintptr_t)SUPSemEventClose }, 234 239 { "SUPSemEventCreate", (void *)(uintptr_t)SUPSemEventCreate }, -
trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h
r71075 r71136 214 214 * @remarks 0x002a0000 is used by 5.1. The next version number must be 0x002b0000. 215 215 */ 216 #define SUPDRV_IOC_VERSION 0x0029000 2216 #define SUPDRV_IOC_VERSION 0x00290003 217 217 218 218 /** SUP_IOCTL_COOKIE. */ -
trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
r70917 r71136 455 455 uint32_t volatile cUsage; 456 456 } SUPDRVUSAGE, *PSUPDRVUSAGE; 457 458 459 /** 460 * I/O control context. 461 */ 462 typedef struct SUPR0IOCTLCTX 463 { 464 /** Magic value (SUPR0IOCTLCTX_MAGIC). */ 465 uint32_t u32Magic; 466 /** Reference counter. */ 467 uint32_t volatile cRefs; 468 #ifdef RT_OS_WINDOWS 469 # ifndef SUPDRV_AGNOSTIC 470 /** The file object, referenced. */ 471 PFILE_OBJECT pFileObject; 472 /** The device object, not referenced. */ 473 PDEVICE_OBJECT pDeviceObject; 474 /** Pointer to fast I/O routine if available. */ 475 FAST_IO_DEVICE_CONTROL *pfnFastIoDeviceControl; 476 # else 477 void *apvPadding[3]; 478 # endif 479 #endif 480 } SUPR0IOCTLCTX; 481 /** Magic value for SUPR0IOCTLCTX (Ahmad Jamal). */ 482 #define SUPR0IOCTLCTX_MAGIC UINT32_C(0x19300702) 457 483 458 484 -
trunk/src/VBox/HostDrivers/Support/SUPLib.cpp
r71075 r71136 277 277 CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION; 278 278 const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00290000 279 ? 0x0029000 2279 ? 0x00290003 280 280 : SUPDRV_IOC_VERSION & 0xffff0000; 281 281 CookieReq.u.In.u32MinVersion = uMinVersion; -
trunk/src/VBox/HostDrivers/Support/SUPLibLdr.cpp
r69500 r71136 167 167 * Only SUPR0 and VMMR0.r0 168 168 */ 169 if ( pszModule 170 && *pszModule 171 && strcmp(pszModule, "VBoxDrv.sys") 172 && strcmp(pszModule, "VMMR0.r0")) 173 { 169 if ( pszModule 170 && *pszModule 171 && strcmp(pszModule, "VBoxDrv.sys") 172 && strcmp(pszModule, "VMMR0.r0")) 173 { 174 #if defined(RT_OS_WINDOWS) && 0 /* Useful for VMMR0 hacking, not for production use. See also SUPDrv-win.cpp */ 175 if (strcmp(pszModule, "ntoskrnl.exe") == 0) 176 { 177 *pValue = 42; /* Non-zero so ring-0 can find the end of the IAT and exclude it when comparing. */ 178 return VINF_SUCCESS; 179 } 180 #endif 174 181 AssertMsgFailed(("%s is importing from %s! (expected 'SUPR0.dll' or 'VMMR0.r0', case-sensitive)\n", pArgs->pszModule, pszModule)); 175 182 return RTErrInfoSetF(pArgs->pErrInfo, VERR_SYMBOL_NOT_FOUND, -
trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
r70917 r71136 2131 2131 } 2132 2132 2133 /** Image compare exclusion regions. */ 2134 typedef struct SUPDRVNTEXCLREGIONS 2135 { 2136 /** Number of regions. */ 2137 uint32_t cRegions; 2138 /** The regions. */ 2139 struct SUPDRVNTEXCLREGION 2140 { 2141 uint32_t uRva; 2142 uint32_t cb; 2143 } aRegions[16]; 2144 } SUPDRVNTEXCLREGIONS; 2145 2146 /** 2147 * Adds an exclusion region to the collection. 2148 */ 2149 static bool supdrvNtAddExclRegion(SUPDRVNTEXCLREGIONS *pRegions, uint32_t uRvaRegion, uint32_t cbRegion) 2150 { 2151 uint32_t const cRegions = pRegions->cRegions; 2152 AssertReturn(cRegions + 1 <= RT_ELEMENTS(pRegions->aRegions), false); 2153 uint32_t i = 0; 2154 for (; i < cRegions; i++) 2155 if (uRvaRegion < pRegions->aRegions[i].uRva) 2156 break; 2157 if (i != cRegions) 2158 memmove(&pRegions->aRegions[i + 1], &pRegions->aRegions[i], (cRegions - i) * sizeof(pRegions->aRegions[0])); 2159 pRegions->aRegions[i].uRva = uRvaRegion; 2160 pRegions->aRegions[i].cb = cbRegion; 2161 pRegions->cRegions++; 2162 return true; 2163 } 2164 2133 2165 2134 2166 int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq) … … 2184 2216 ) 2185 2217 { 2186 struct MyRegion 2187 { 2188 uint32_t uRva; 2189 uint32_t cb; 2190 } aExcludeRgns[16]; 2191 unsigned cExcludeRgns = 0; 2218 SUPDRVNTEXCLREGIONS ExcludeRegions; 2219 ExcludeRegions.cRegions = 0; 2192 2220 2193 2221 /* ImageBase: */ … … 2195 2223 && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage 2196 2224 || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) ) 2197 { 2198 aExcludeRgns[cExcludeRgns].uRva = offImageBase; 2199 aExcludeRgns[cExcludeRgns].cb = cbImageBase; 2200 cExcludeRgns++; 2201 } 2225 supdrvNtAddExclRegion(&ExcludeRegions, offImageBase, cbImageBase); 2202 2226 2203 2227 /* Imports: */ … … 2208 2232 IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps); 2209 2233 while ( cImpsLeft-- > 0 2210 && cExcludeRgns < RT_ELEMENTS(aExcludeRgns))2234 && ExcludeRegions.cRegions < RT_ELEMENTS(ExcludeRegions.aRegions)) 2211 2235 { 2212 2236 uint32_t uRvaThunk = pImp->OriginalFirstThunk; 2213 if ( 2214 && 2215 && 2237 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS) 2238 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA) 2239 && uRvaThunk != pImp->FirstThunk) 2216 2240 { 2217 2241 /* Find the size of the thunk table. */ … … 2221 2245 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0) 2222 2246 cThunks++; 2223 2224 /* Ordered table insert. */ 2225 unsigned i = 0; 2226 for (; i < cExcludeRgns; i++) 2227 if (uRvaThunk < aExcludeRgns[i].uRva) 2228 break; 2229 if (i != cExcludeRgns) 2230 memmove(&aExcludeRgns[i + 1], &aExcludeRgns[i], (cExcludeRgns - i) * sizeof(aExcludeRgns[0])); 2231 aExcludeRgns[i].uRva = uRvaThunk; 2232 aExcludeRgns[i].cb = cThunks * sizeof(IMAGE_THUNK_DATA); 2233 cExcludeRgns++; 2247 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA)); 2234 2248 } 2249 2250 #if 0 /* Useful for VMMR0 hacking, not for production use. See also SUPDrvLdr.cpp. */ 2251 /* Exclude the other thunk table if ntoskrnl.exe. */ 2252 uint32_t uRvaName = pImp->Name; 2253 if ( uRvaName > sizeof(IMAGE_NT_HEADERS) 2254 && uRvaName < pImage->cbImageBits - sizeof("ntoskrnl.exe") 2255 && memcmp(&pbImageBits[uRvaName], RT_STR_TUPLE("ntoskrnl.exe")) == 0) 2256 { 2257 uRvaThunk = pImp->FirstThunk; 2258 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS) 2259 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)) 2260 { 2261 /* Find the size of the thunk table. */ 2262 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk); 2263 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA); 2264 uint32_t cThunks = 0; 2265 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0) 2266 cThunks++; 2267 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA)); 2268 } 2269 } 2270 #endif 2235 2271 2236 2272 /* advance */ … … 2243 2279 int iDiff = 0; 2244 2280 uint32_t uRvaNext = 0; 2245 for (unsigned i = 0; !iDiff && i < cExcludeRgns; i++)2246 { 2247 if (uRvaNext < aExcludeRgns[i].uRva)2248 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, aExcludeRgns[i].uRva - uRvaNext, pReq);2249 uRvaNext = aExcludeRgns[i].uRva + aExcludeRgns[i].cb;2281 for (unsigned i = 0; !iDiff && i < ExcludeRegions.cRegions; i++) 2282 { 2283 if (uRvaNext < ExcludeRegions.aRegions[i].uRva) 2284 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, ExcludeRegions.aRegions[i].uRva - uRvaNext, pReq); 2285 uRvaNext = ExcludeRegions.aRegions[i].uRva + ExcludeRegions.aRegions[i].cb; 2250 2286 } 2251 2287 if (!iDiff && uRvaNext < pImage->cbImageBits) … … 2558 2594 { 2559 2595 return 0; 2596 } 2597 2598 2599 SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx) 2600 { 2601 /* 2602 * Validate input. 2603 */ 2604 AssertPtrReturn(ppCtx, VERR_INVALID_POINTER); 2605 *ppCtx = NULL; 2606 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER); 2607 AssertReturn(!fFlags, VERR_INVALID_FLAGS); 2608 2609 /* 2610 * Turn the partition handle into a file object and related device object 2611 * so that we can issue direct I/O control calls to the pair later. 2612 */ 2613 PFILE_OBJECT pFileObject = NULL; 2614 OBJECT_HANDLE_INFORMATION HandleInfo = { 0, 0 }; 2615 NTSTATUS rcNt = ObReferenceObjectByHandle((HANDLE)hHandle, /*FILE_WRITE_DATA*/0, *IoFileObjectType, 2616 UserMode, (void **)&pFileObject, &HandleInfo); 2617 if (!NT_SUCCESS(rcNt)) 2618 return RTErrConvertFromNtStatus(rcNt); 2619 AssertPtrReturn(pFileObject, VERR_INTERNAL_ERROR_3); 2620 2621 PDEVICE_OBJECT pDevObject = IoGetRelatedDeviceObject(pFileObject); 2622 AssertMsgReturnStmt(RT_VALID_PTR(pDevObject), ("pDevObject=%p\n", pDevObject), 2623 ObDereferenceObject(pFileObject), VERR_INTERNAL_ERROR_2); 2624 2625 /* 2626 * Allocate a context structure and fill it in. 2627 */ 2628 PSUPR0IOCTLCTX pCtx = (PSUPR0IOCTLCTX)RTMemAllocZ(sizeof(*pCtx)); 2629 if (pCtx) 2630 { 2631 pCtx->u32Magic = SUPR0IOCTLCTX_MAGIC; 2632 pCtx->cRefs = 1; 2633 pCtx->pFileObject = pFileObject; 2634 pCtx->pDeviceObject = pDevObject; 2635 2636 PDRIVER_OBJECT pDrvObject = pDevObject->DriverObject; 2637 if ( RT_VALID_PTR(pDrvObject->FastIoDispatch) 2638 && RT_VALID_PTR(pDrvObject->FastIoDispatch->FastIoDeviceControl)) 2639 pCtx->pfnFastIoDeviceControl = pDrvObject->FastIoDispatch->FastIoDeviceControl; 2640 else 2641 pCtx->pfnFastIoDeviceControl = NULL; 2642 *ppCtx = pCtx; 2643 return VINF_SUCCESS; 2644 } 2645 2646 ObDereferenceObject(pFileObject); 2647 return VERR_NO_MEMORY; 2648 } 2649 2650 2651 /** 2652 * I/O control destructor for NT. 2653 * 2654 * @param pCtx The context to destroy. 2655 */ 2656 static void supdrvNtIoCtlContextDestroy(PSUPR0IOCTLCTX pCtx) 2657 { 2658 PFILE_OBJECT pFileObject = pCtx->pFileObject; 2659 pCtx->pfnFastIoDeviceControl = NULL; 2660 pCtx->pFileObject = NULL; 2661 pCtx->pDeviceObject = NULL; 2662 ASMAtomicWriteU32(&pCtx->u32Magic, ~SUPR0IOCTLCTX_MAGIC); 2663 2664 if (RT_VALID_PTR(pFileObject)) 2665 ObDereferenceObject(pFileObject); 2666 RTMemFree(pCtx); 2667 } 2668 2669 2670 SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx) 2671 { 2672 if (pCtx != NULL) 2673 { 2674 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 2675 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER); 2676 2677 uint32_t cRefs = ASMAtomicDecU32(&pCtx->cRefs); 2678 Assert(cRefs < _4K); 2679 if (cRefs == 0) 2680 supdrvNtIoCtlContextDestroy(pCtx); 2681 } 2682 return VINF_SUCCESS; 2683 } 2684 2685 2686 SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction, 2687 void *pvInput, RTR3PTR pvInputUser, size_t cbInput, 2688 void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput, 2689 int32_t *piNativeRc) 2690 { 2691 AssertPtrReturn(pCtx, VERR_INVALID_POINTER); 2692 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER); 2693 2694 /* Reference the context. */ 2695 uint32_t cRefs = ASMAtomicIncU32(&pCtx->cRefs); 2696 Assert(cRefs > 1 && cRefs < _4K); 2697 2698 /* 2699 * Try fast I/O control path first. 2700 */ 2701 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; 2702 if (pCtx->pfnFastIoDeviceControl) 2703 { 2704 /* Must pass user addresses here as that's what's being expected. */ 2705 BOOLEAN fHandled = pCtx->pfnFastIoDeviceControl(pCtx->pFileObject, 2706 TRUE /*Wait*/, 2707 (void *)pvInputUser, (ULONG)cbInput, 2708 (void *)pvOutputUser, (ULONG)cbOutput, 2709 uFunction, 2710 &Ios, 2711 pCtx->pDeviceObject); 2712 if (fHandled) 2713 { 2714 /* Relase the context. */ 2715 cRefs = ASMAtomicDecU32(&pCtx->cRefs); 2716 Assert(cRefs < _4K); 2717 if (cRefs == 0) 2718 supdrvNtIoCtlContextDestroy(pCtx); 2719 2720 /* Set/convert status and return. */ 2721 if (piNativeRc) 2722 { 2723 *piNativeRc = Ios.Status; 2724 return VINF_SUCCESS; 2725 } 2726 if (NT_SUCCESS(Ios.Status)) 2727 return VINF_SUCCESS; 2728 return RTErrConvertFromNtStatus(Ios.Status); 2729 } 2730 2731 /* 2732 * Fall back on IRP if not handled. 2733 * 2734 * Note! Perhaps we should rather fail, because VID.SYS will crash getting 2735 * the partition ID with the code below. It tries to zero the output 2736 * buffer as if it were as system buffer... 2737 */ 2738 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 2739 } 2740 2741 /* 2742 * For directly accessed buffers we must supply user mode addresses or 2743 * we'll fail ProbeForWrite validation. 2744 */ 2745 switch (uFunction & 3) 2746 { 2747 case METHOD_BUFFERED: 2748 /* For buffered accesses, we can supply kernel buffers. */ 2749 break; 2750 2751 case METHOD_IN_DIRECT: 2752 pvInput = (void *)pvInputUser; 2753 break; 2754 2755 case METHOD_NEITHER: 2756 pvInput = (void *)pvInputUser; 2757 RT_FALL_THRU(); 2758 2759 case METHOD_OUT_DIRECT: 2760 pvOutput = (void *)pvOutputUser; 2761 break; 2762 } 2763 2764 /* 2765 * Build the request. 2766 */ 2767 int rc; 2768 KEVENT Event; 2769 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2770 2771 PIRP pIrp = IoBuildDeviceIoControlRequest(uFunction, pCtx->pDeviceObject, 2772 pvInput, (ULONG)cbInput, pvOutput, (ULONG)cbOutput, 2773 FALSE /* InternalDeviceControl */, &Event, &Ios); 2774 if (pIrp) 2775 { 2776 IoGetNextIrpStackLocation(pIrp)->FileObject = pCtx->pFileObject; 2777 2778 /* 2779 * Make the call. 2780 */ 2781 NTSTATUS rcNt = IoCallDriver(pCtx->pDeviceObject, pIrp); 2782 if (rcNt == STATUS_PENDING) 2783 { 2784 rcNt = KeWaitForSingleObject(&Event, /* Object */ 2785 Executive, /* WaitReason */ 2786 KernelMode, /* WaitMode */ 2787 FALSE, /* Alertable */ 2788 NULL); /* TimeOut */ 2789 AssertMsg(rcNt == STATUS_SUCCESS, ("rcNt=%#x\n", rcNt)); 2790 rcNt = Ios.Status; 2791 } 2792 else if (NT_SUCCESS(rcNt) && Ios.Status != STATUS_SUCCESS) 2793 rcNt = Ios.Status; 2794 2795 /* Set/convert return code. */ 2796 if (piNativeRc) 2797 { 2798 *piNativeRc = rcNt; 2799 rc = VINF_SUCCESS; 2800 } 2801 else if (NT_SUCCESS(rcNt)) 2802 rc = VINF_SUCCESS; 2803 else 2804 rc = RTErrConvertFromNtStatus(rcNt); 2805 } 2806 else 2807 { 2808 if (piNativeRc) 2809 *piNativeRc = STATUS_NO_MEMORY; 2810 rc = VERR_NO_MEMORY; 2811 } 2812 2813 /* Relase the context. */ 2814 cRefs = ASMAtomicDecU32(&pCtx->cRefs); 2815 Assert(cRefs < _4K); 2816 if (cRefs == 0) 2817 supdrvNtIoCtlContextDestroy(pCtx); 2818 2819 return rc; 2560 2820 } 2561 2821 -
trunk/src/VBox/VMM/Makefile.kmk
r71129 r71136 830 830 VMMR0/VMMR0JmpA-x86.asm 831 831 832 if1of ($(USERNAME),bird) # experimental.833 VMMR0_SOURCES.win.amd64 += VMMR0/NEMR0Native-win.cpp834 VMMR0_DEFS.win.amd64 += VBOX_WITH_NATIVE_NEM VBOX_WITH_NEM_R0835 endif836 837 832 VMMR0_LIBS = \ 838 833 $(PATH_STAGE_LIB)/ServicesR0$(VBOX_SUFF_LIB) \ … … 842 837 VMMR0_LIBS += \ 843 838 $(PATH_STAGE_LIB)/SUPR0$(VBOX_SUFF_LIB) 839 endif 840 if1of ($(USERNAME),bird) # experimental. 841 VMMR0_SOURCES.win.amd64 += VMMR0/NEMR0Native-win.cpp 842 VMMR0_DEFS.win.amd64 += VBOX_WITH_NATIVE_NEM VBOX_WITH_NEM_R0 843 VMMR0/NEMR0Native-win.cpp_SDKS.win = ReorderCompilerIncs $(VBOX_WINDDK) $(VBOX_WINPSDK)INCS 844 844 endif 845 845 -
trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp
r71130 r71136 21 21 *********************************************************************************************************************************/ 22 22 #define LOG_GROUP LOG_GROUP_NEM 23 #include <iprt/nt/nt.h> 23 24 #include <iprt/nt/hyperv.h> 25 #include <iprt/nt/vid.h> 24 26 25 27 #include <VBox/vmm/nem.h> … … 50 52 * Global Variables * 51 53 *********************************************************************************************************************************/ 52 static uint64_t (* 54 static uint64_t (*g_pfnHvlInvokeHypercall)(uint64_t uCallInfo, uint64_t HCPhysInput, uint64_t HCPhysOutput); 53 55 54 56 … … 64 66 VMMR0_INT_DECL(int) NEMR0InitVM(PGVM pGVM, PVM pVM) 65 67 { 68 AssertCompile(sizeof(pGVM->nem.s) <= sizeof(pGVM->nem.padding)); 69 AssertCompile(sizeof(pGVM->aCpus[0].nem.s) <= sizeof(pGVM->aCpus[0].nem.padding)); 70 66 71 int rc = GVMMR0ValidateGVMandVMandEMT(pGVM, pVM, 0); 67 72 AssertRCReturn(rc, rc); … … 112 117 * So far, so good. 113 118 */ 114 /** @todo would be good if we could establish the partition ID ourselves. */115 /** @todo this is too EARLY! */116 pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;117 119 return rc; 118 120 } … … 122 124 123 125 RT_NOREF(pGVM, pVM); 126 return rc; 127 } 128 129 130 /** 131 * Perform an I/O control operation on the partition handle (VID.SYS). 132 * 133 * @returns NT status code. 134 * @param pGVM The ring-0 VM structure. 135 * @param uFunction The function to perform. 136 * @param pvInput The input buffer. This must point within the VM 137 * structure so we can easily convert to a ring-3 138 * pointer if necessary. 139 * @param cbInput The size of the input. @a pvInput must be NULL when 140 * zero. 141 * @param pvOutput The output buffer. This must also point within the 142 * VM structure for ring-3 pointer magic. 143 * @param cbOutput The size of the output. @a pvOutput must be NULL 144 * when zero. 145 */ 146 DECLINLINE(NTSTATUS) nemR0NtPerformIoControl(PGVM pGVM, uint32_t uFunction, void *pvInput, uint32_t cbInput, 147 void *pvOutput, uint32_t cbOutput) 148 { 149 #ifdef RT_STRICT 150 /* 151 * Input and output parameters are part of the VM CPU structure. 152 */ 153 PVM pVM = pGVM->pVM; 154 size_t const cbVM = RT_UOFFSETOF(VM, aCpus[pGVM->cCpus]); 155 if (pvInput) 156 AssertReturn(((uintptr_t)pvInput + cbInput) - (uintptr_t)pVM <= cbVM, VERR_INVALID_PARAMETER); 157 if (pvOutput) 158 AssertReturn(((uintptr_t)pvOutput + cbOutput) - (uintptr_t)pVM <= cbVM, VERR_INVALID_PARAMETER); 159 #endif 160 161 int32_t rcNt = STATUS_UNSUCCESSFUL; 162 int rc = SUPR0IoCtlPerform(pGVM->nem.s.pIoCtlCtx, uFunction, 163 pvInput, 164 pvInput ? (uintptr_t)pvInput + pGVM->nem.s.offRing3ConversionDelta : NIL_RTR3PTR, 165 cbInput, 166 pvOutput, 167 pvOutput ? (uintptr_t)pvOutput + pGVM->nem.s.offRing3ConversionDelta : NIL_RTR3PTR, 168 cbOutput, 169 &rcNt); 170 if (RT_SUCCESS(rc) || !NT_SUCCESS((NTSTATUS)rcNt)) 171 return (NTSTATUS)rcNt; 172 return STATUS_UNSUCCESSFUL; 173 } 174 175 176 /** 177 * 2nd part of the initialization, after we've got a partition handle. 178 * 179 * @returns VBox status code. 180 * @param pGVM The ring-0 VM handle. 181 * @param pVM The cross context VM handle. 182 * @thread EMT(0) 183 */ 184 VMMR0_INT_DECL(int) NEMR0InitVMPart2(PGVM pGVM, PVM pVM) 185 { 186 int rc = GVMMR0ValidateGVMandVMandEMT(pGVM, pVM, 0); 187 AssertRCReturn(rc, rc); 188 SUPR0Printf("NEMR0InitVMPart2\n"); LogRel(("2: NEMR0InitVMPart2\n")); 189 190 /* 191 * Copy and validate the I/O control information from ring-3. 192 */ 193 NEMWINIOCTL Copy = pVM->nem.s.IoCtlGetHvPartitionId; 194 AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED); 195 AssertLogRelReturn(Copy.cbInput == 0, VERR_NEM_INIT_FAILED); 196 AssertLogRelReturn(Copy.cbOutput == sizeof(HV_PARTITION_ID), VERR_NEM_INIT_FAILED); 197 pGVM->nem.s.IoCtlGetHvPartitionId = Copy; 198 199 Copy = pVM->nem.s.IoCtlStartVirtualProcessor; 200 AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED); 201 AssertLogRelReturn(Copy.cbInput == sizeof(HV_VP_INDEX), VERR_NEM_INIT_FAILED); 202 AssertLogRelReturn(Copy.cbOutput == 0, VERR_NEM_INIT_FAILED); 203 AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, VERR_NEM_INIT_FAILED); 204 pGVM->nem.s.IoCtlStartVirtualProcessor = Copy; 205 206 Copy = pVM->nem.s.IoCtlStopVirtualProcessor; 207 AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED); 208 AssertLogRelReturn(Copy.cbInput == sizeof(HV_VP_INDEX), VERR_NEM_INIT_FAILED); 209 AssertLogRelReturn(Copy.cbOutput == 0, VERR_NEM_INIT_FAILED); 210 AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, VERR_NEM_INIT_FAILED); 211 AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlStartVirtualProcessor.uFunction, VERR_NEM_INIT_FAILED); 212 pGVM->nem.s.IoCtlStopVirtualProcessor = Copy; 213 214 Copy = pVM->nem.s.IoCtlMessageSlotHandleAndGetNext; 215 AssertLogRelReturn(Copy.uFunction != 0, VERR_NEM_INIT_FAILED); 216 AssertLogRelReturn(Copy.cbInput == sizeof(VID_IOCTL_INPUT_MESSAGE_SLOT_HANDLE_AND_GET_NEXT), VERR_NEM_INIT_FAILED); 217 AssertLogRelReturn(Copy.cbOutput == 0, VERR_NEM_INIT_FAILED); 218 AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, VERR_NEM_INIT_FAILED); 219 AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlStartVirtualProcessor.uFunction, VERR_NEM_INIT_FAILED); 220 AssertLogRelReturn(Copy.uFunction != pGVM->nem.s.IoCtlStopVirtualProcessor.uFunction, VERR_NEM_INIT_FAILED); 221 pGVM->nem.s.IoCtlMessageSlotHandleAndGetNext = Copy; 222 223 /* 224 * Setup of an I/O control context for the partition handle for later use. 225 */ 226 rc = SUPR0IoCtlSetupForHandle(pGVM->pSession, pVM->nem.s.hPartitionDevice, 0, &pGVM->nem.s.pIoCtlCtx); 227 AssertLogRelRCReturn(rc, rc); 228 pGVM->nem.s.offRing3ConversionDelta = (uintptr_t)pVM->pVMR3 - (uintptr_t)pGVM->pVM; 229 230 /* 231 * Get the partition ID. 232 */ 233 PVMCPU pVCpu = &pGVM->pVM->aCpus[0]; 234 NTSTATUS rcNt = nemR0NtPerformIoControl(pGVM, pGVM->nem.s.IoCtlGetHvPartitionId.uFunction, NULL, 0, 235 &pVCpu->nem.s.uIoCtlBuf.idPartition, sizeof(pVCpu->nem.s.uIoCtlBuf.idPartition)); 236 AssertLogRelMsgReturn(NT_SUCCESS(rcNt), ("IoCtlGetHvPartitionId failed: %#x\n", rcNt), VERR_NEM_INIT_FAILED); 237 pGVM->nem.s.idHvPartition = pVCpu->nem.s.uIoCtlBuf.idPartition; 238 AssertLogRelMsgReturn(pGVM->nem.s.idHvPartition == pVM->nem.s.idHvPartition, 239 ("idHvPartition mismatch: r0=%#RX64, r3=%#RX64\n", pGVM->nem.s.idHvPartition, pVM->nem.s.idHvPartition), 240 VERR_NEM_INIT_FAILED); 241 242 124 243 return rc; 125 244 } … … 137 256 { 138 257 pGVM->nem.s.idHvPartition = HV_PARTITION_ID_INVALID; 258 259 /* Clean up I/O control context. */ 260 if (pGVM->nem.s.pIoCtlCtx) 261 { 262 int rc = SUPR0IoCtlCleanup(pGVM->nem.s.pIoCtlCtx); 263 AssertRC(rc); 264 pGVM->nem.s.pIoCtlCtx = NULL; 265 } 139 266 140 267 /* Free the hypercall pages. */ … … 195 322 AssertReturn(GCPhysSrc < _1E, VERR_OUT_OF_RANGE); 196 323 } 197 198 /** @todo fix pGVM->nem.s.idHvPartition init. */199 if (pGVM->nem.s.idHvPartition == 0)200 pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;201 324 202 325 /* … … 291 414 AssertMsgReturn(!(GCPhys & X86_PAGE_OFFSET_MASK), ("%RGp\n", GCPhys), VERR_OUT_OF_RANGE); 292 415 AssertReturn(GCPhys < _1E, VERR_OUT_OF_RANGE); 293 294 /** @todo fix pGVM->nem.s.idHvPartition init. */295 if (pGVM->nem.s.idHvPartition == 0)296 pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;297 416 298 417 /* … … 732 851 AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API); 733 852 734 /** @todo fix pGVM->nem.s.idHvPartition init. */735 if (pGVM->nem.s.idHvPartition == 0)736 pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;737 738 853 /* 739 854 * Call worker. … … 1146 1261 AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API); 1147 1262 1148 /** @todo fix pGVM->nem.s.idHvPartition init. */1149 if (pGVM->nem.s.idHvPartition == 0)1150 pGVM->nem.s.idHvPartition = pVM->nem.s.idHvPartition;1151 1152 1263 /* 1153 1264 * Call worker. -
trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
r71087 r71136 1975 1975 break; 1976 1976 1977 case VMMR0_DO_NEM_INIT_VM_PART_2: 1978 if (u64Arg || pReqHdr || idCpu != 0) 1979 return VERR_INVALID_PARAMETER; 1980 rc = NEMR0InitVMPart2(pGVM, pVM); 1981 VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING); 1982 break; 1983 1977 1984 case VMMR0_DO_NEM_MAP_PAGES: 1978 1985 if (u64Arg || pReqHdr || idCpu == NIL_VMCPUID) -
trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
r71131 r71136 1269 1269 pVM->nem.s.fCreatedEmts = true; 1270 1270 1271 LogRel(("NEM: Successfully set up partition (device handle %p, partition ID %#llx)\n", hPartitionDevice, idHvPartition)); 1272 return VINF_SUCCESS; 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); 1273 1281 } 1274 1282 … … 1342 1350 } 1343 1351 } 1344 1345 1352 1346 1353 #ifdef NEM_WIN_USE_HYPERCALLS_FOR_PAGES … … 2295 2302 /* ACK the stop message. */ 2296 2303 fWait = g_pfnVidMessageSlotHandleAndGetNext(pVM->nem.s.hPartitionDevice, pVCpu->idCpu, 2297 2304 VID_MSHAGN_F_HANDLE_MESSAGE, 5000); 2298 2305 AssertLogRelMsg(fWait, ("dwErr=%u (%#x) rcNt=%#x\n", RTNtLastErrorValue(), RTNtLastErrorValue(), RTNtLastStatusValue())); 2299 2306 -
trunk/src/VBox/VMM/include/NEMInternal.h
r71131 r71136 173 173 } UnmapPages; 174 174 } Hypercall; 175 /** I/O control buffer, we always use this for I/O controls. */ 176 union 177 { 178 uint8_t ab[64]; 179 HV_PARTITION_ID idPartition; 180 } uIoCtlBuf; 175 181 #endif 176 182 } NEMCPU; … … 232 238 /** The partition ID. */ 233 239 uint64_t idHvPartition; 240 /** I/O control context. */ 241 PSUPR0IOCTLCTX pIoCtlCtx; 242 /** Delta to add to convert a ring-0 pointer to a ring-3 one. */ 243 uintptr_t offRing3ConversionDelta; 244 /** Info about the VidGetHvPartitionId I/O control interface. */ 245 NEMWINIOCTL IoCtlGetHvPartitionId; 246 /** Info about the VidStartVirtualProcessor I/O control interface. */ 247 NEMWINIOCTL IoCtlStartVirtualProcessor; 248 /** Info about the VidStopVirtualProcessor I/O control interface. */ 249 NEMWINIOCTL IoCtlStopVirtualProcessor; 250 /** Info about the VidStopVirtualProcessor I/O control interface. */ 251 NEMWINIOCTL IoCtlMessageSlotHandleAndGetNext; 252 234 253 # else 235 254 uint32_t uDummy;
Note:
See TracChangeset
for help on using the changeset viewer.