Changeset 70942 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Feb 9, 2018 7:44:03 PM (7 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/Makefile.kmk
r70918 r70942 308 308 VMMSwitcher/AMD64Stub.asm 309 309 310 VBoxVMM_SOURCES.win += VMMR3/NEMR3Native-win.cpp 311 VBoxVMM_DEFS.win += VBOX_WITH_NATIVE_NEM 310 if1of ($(USERNAME),bird) # experimental. 311 VBoxVMM_SOURCES.win.amd64 += VMMR3/NEMR3Native-win.cpp 312 VBoxVMM_DEFS.win.amd64 += VBOX_WITH_NATIVE_NEM 313 VMMR3/NEMR3Native-win.cpp_DEFS.amd64 = _AMD64_ 314 VMMR3/NEMR3Native-win.cpp_INCS = \ 315 $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17083.0/include/10.0.17083.0/um \ 316 $(KBUILD_DEVTOOLS)/win.x86/sdk/v10.0.17083.0/include/10.0.17083.0/shared 317 endif 312 318 313 319 VBoxVMM_LIBS = \ -
trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
r70918 r70942 21 21 *********************************************************************************************************************************/ 22 22 #define LOG_GROUP LOG_GROUP_NEM 23 #include <WinHvPlatform.h> 24 25 #ifndef _WIN32_WINNT_WIN10 26 # error "Missing _WIN32_WINNT_WIN10" 27 #endif 28 #ifndef _WIN32_WINNT_WIN10_RS1 /* Missing define, causing trouble for us. */ 29 # define _WIN32_WINNT_WIN10_RS1 (_WIN32_WINNT_WIN10 + 1) 30 #endif 31 #include <sysinfoapi.h> 32 #include <fileapi.h> 33 #include <errhandlingapi.h> 34 #include <winerror.h> /* no api header for this. */ 35 23 36 #include <VBox/vmm/nem.h> 24 37 #include "NEMInternal.h" 25 38 #include <VBox/vmm/vm.h> 26 39 40 #include <iprt/ldr.h> 41 #include <iprt/path.h> 42 #include <iprt/string.h> 43 44 45 /********************************************************************************************************************************* 46 * Global Variables * 47 *********************************************************************************************************************************/ 48 /** @name APIs imported from WinHvPlatform.dll 49 * @{ */ 50 static decltype(WHvGetCapability) * g_pfnWHvGetCapability; 51 static decltype(WHvCreatePartition) * g_pfnWHvCreatePartition; 52 static decltype(WHvSetupPartition) * g_pfnWHvSetupPartition; 53 static decltype(WHvDeletePartition) * g_pfnWHvDeletePartition; 54 static decltype(WHvGetPartitionProperty) * g_pfnWHvGetPartitionProperty; 55 static decltype(WHvSetPartitionProperty) * g_pfnWHvSetPartitionProperty; 56 static decltype(WHvMapGpaRange) * g_pfnWHvMapGpaRange; 57 static decltype(WHvUnmapGpaRange) * g_pfnWHvUnmapGpaRange; 58 static decltype(WHvTranslateGva) * g_pfnWHvTranslateGva; 59 static decltype(WHvCreateVirtualProcessor) * g_pfnWHvCreateVirtualProcessor; 60 static decltype(WHvDeleteVirtualProcessor) * g_pfnWHvDeleteVirtualProcessor; 61 static decltype(WHvRunVirtualProcessor) * g_pfnWHvRunVirtualProcessor; 62 static decltype(WHvGetRunExitContextSize) * g_pfnWHvGetRunExitContextSize; 63 static decltype(WHvCancelRunVirtualProcessor) * g_pfnWHvCancelRunVirtualProcessor; 64 static decltype(WHvGetVirtualProcessorRegisters) * g_pfnWHvGetVirtualProcessorRegisters; 65 static decltype(WHvSetVirtualProcessorRegisters) * g_pfnWHvSetVirtualProcessorRegisters; 66 /** @} */ 67 68 69 /** 70 * Import instructions. 71 */ 72 static const struct 73 { 74 uint8_t idxDll; /**< 0 for WinHvPlatform.dll, 1 for vid.dll. */ 75 bool fOptional; /**< Set if import is optional. */ 76 PFNRT *ppfn; /**< The function pointer variable. */ 77 const char *pszName; /**< The function name. */ 78 } g_aImports[] = 79 { 80 #define NEM_WIN_IMPORT(a_idxDll, a_fOptional, a_Name) { (a_idxDll), (a_fOptional), (PFNRT *)&RT_CONCAT(g_pfn,a_Name), #a_Name } 81 NEM_WIN_IMPORT(0, false, WHvGetCapability), 82 NEM_WIN_IMPORT(0, false, WHvCreatePartition), 83 NEM_WIN_IMPORT(0, false, WHvSetupPartition), 84 NEM_WIN_IMPORT(0, false, WHvDeletePartition), 85 NEM_WIN_IMPORT(0, false, WHvGetPartitionProperty), 86 NEM_WIN_IMPORT(0, false, WHvSetPartitionProperty), 87 NEM_WIN_IMPORT(0, false, WHvMapGpaRange), 88 NEM_WIN_IMPORT(0, false, WHvUnmapGpaRange), 89 NEM_WIN_IMPORT(0, false, WHvTranslateGva), 90 NEM_WIN_IMPORT(0, false, WHvCreateVirtualProcessor), 91 NEM_WIN_IMPORT(0, false, WHvDeleteVirtualProcessor), 92 NEM_WIN_IMPORT(0, false, WHvRunVirtualProcessor), 93 NEM_WIN_IMPORT(0, false, WHvGetRunExitContextSize), 94 NEM_WIN_IMPORT(0, false, WHvCancelRunVirtualProcessor), 95 NEM_WIN_IMPORT(0, false, WHvGetVirtualProcessorRegisters), 96 NEM_WIN_IMPORT(0, false, WHvSetVirtualProcessorRegisters), 97 #undef NEM_WIN_IMPORT 98 }; 99 100 101 /* 102 * Let the preprocessor alias the APIs to import variables for better autocompletion. 103 */ 104 #ifndef IN_SLICKEDIT 105 # define WHvGetCapability g_pfnWHvGetCapability 106 # define WHvCreatePartition g_pfnWHvCreatePartition 107 # define WHvSetupPartition g_pfnWHvSetupPartition 108 # define WHvDeletePartition g_pfnWHvDeletePartition 109 # define WHvGetPartitionProperty g_pfnWHvGetPartitionProperty 110 # define WHvSetPartitionProperty g_pfnWHvSetPartitionProperty 111 # define WHvMapGpaRange g_pfnWHvMapGpaRange 112 # define WHvUnmapGpaRange g_pfnWHvUnmapGpaRange 113 # define WHvTranslateGva g_pfnWHvTranslateGva 114 # define WHvCreateVirtualProcessor g_pfnWHvCreateVirtualProcessor 115 # define WHvDeleteVirtualProcessor g_pfnWHvDeleteVirtualProcessor 116 # define WHvRunVirtualProcessor g_pfnWHvRunVirtualProcessor 117 # define WHvGetRunExitContextSize g_pfnWHvGetRunExitContextSize 118 # define WHvCancelRunVirtualProcessor g_pfnWHvCancelRunVirtualProcessor 119 # define WHvGetVirtualProcessorRegisters g_pfnWHvGetVirtualProcessorRegisters 120 # define WHvSetVirtualProcessorRegisters g_pfnWHvSetVirtualProcessorRegisters 121 #endif 122 27 123 28 124 29 125 int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced) 30 126 { 31 NOREF(pVM); NOREF(fFallback); NOREF(fForced); 127 /* 128 * Error state. 129 * 130 * The error message will be non-empty on failure, 'rc' may or may not 131 * be set. Early API detection failures will not set 'rc', so we'll sort 132 * that out at the other end of the function. 133 */ 134 RTERRINFOSTATIC ErrInfo; 135 int rc = VINF_SUCCESS; 136 PRTERRINFO pErrInfo = RTErrInfoInitStatic(&ErrInfo); 137 138 /* 139 * Check that the DLL files we need are present, but without loading them. 140 * We'd like to avoid loading them unnecessarily. 141 */ 142 WCHAR wszPath[MAX_PATH + 64]; 143 UINT cwcPath = GetSystemDirectoryW(wszPath, MAX_PATH); 144 if (cwcPath >= MAX_PATH || cwcPath < 2) 145 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "GetSystemDirectoryW failed (%#x / %u)", cwcPath, GetLastError()); 146 else 147 { 148 if (wszPath[cwcPath - 1] != '\\' || wszPath[cwcPath - 1] != '/') 149 wszPath[cwcPath++] = '\\'; 150 RTUtf16CopyAscii(&wszPath[cwcPath], RT_ELEMENTS(wszPath) - cwcPath, "WinHvPlatform.dll"); 151 if (GetFileAttributesW(wszPath) == INVALID_FILE_ATTRIBUTES) 152 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "The native API dll was not found (%ls)", wszPath); 153 else 154 { 155 /* 156 * Check that we're in a VM and that the hypervisor identifies itself as Hyper-V. 157 */ 158 if (!ASMHasCpuId()) 159 rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID support"); 160 else if (!ASMIsValidStdRange(ASMCpuId_EAX(0))) 161 rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "No CPUID leaf #1"); 162 else if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP)) 163 rc = RTErrInfoSet(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Not in a hypervisor partition (HVP=0)"); 164 else 165 { 166 uint32_t cMaxHyperLeaf = 0; 167 uint32_t uEbx = 0; 168 uint32_t uEcx = 0; 169 uint32_t uEdx = 0; 170 ASMCpuIdExSlow(0x40000000, 0, 0, 0, &cMaxHyperLeaf, &uEbx, &uEcx, &uEdx); 171 if (!ASMIsValidHypervisorRange(cMaxHyperLeaf)) 172 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Invalid hypervisor CPUID range (%#x %#x %#x %#x)", 173 cMaxHyperLeaf, uEbx, uEcx, uEdx); 174 else if ( uEbx != UINT32_C(0x7263694d) /* Micr */ 175 || uEcx != UINT32_C(0x666f736f) /* osof */ 176 || uEdx != UINT32_C(0x76482074) /* t Hv */) 177 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, 178 "Not Hyper-V CPUID signature: %#x %#x %#x (expected %#x %#x %#x)", 179 uEbx, uEcx, uEdx, UINT32_C(0x7263694d), UINT32_C(0x666f736f), UINT32_C(0x76482074)); 180 else if (cMaxHyperLeaf < UINT32_C(0x40000005)) 181 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, "Too narrow hypervisor CPUID range (%#x)", cMaxHyperLeaf); 182 else 183 { 184 /** @todo would be great if we could recognize a root partition from the 185 * CPUID info, but I currently don't dare do that. */ 186 187 /* 188 * Now try load the DLLs and resolve the APIs. 189 */ 190 static const char * const s_pszDllPrefixes[] = { "WinHvPlatform.dll!", "vid.dll!" }; 191 RTLDRMOD ahMods[2] = { NIL_RTLDRMOD, NIL_RTLDRMOD }; 192 rc = RTLdrLoadSystem("vid.dll", true /*fNoUnload*/, &ahMods[1]); 193 if (RT_SUCCESS(rc)) 194 { 195 rc = RTLdrLoadSystem("WinHvPlatform.dll", true /*fNoUnload*/, &ahMods[0]); 196 if (RT_SUCCESS(rc)) 197 { 198 for (unsigned i = 0; i < RT_ELEMENTS(g_aImports); i++) 199 { 200 int rc2 = RTLdrGetSymbol(ahMods[g_aImports[i].idxDll], g_aImports[i].pszName, 201 (void **)g_aImports[i].ppfn); 202 if (RT_FAILURE(rc2)) 203 { 204 *g_aImports[i].ppfn = NULL; 205 206 LogRel(("NEM: %s: Failed to import %s%s: %Rrc", 207 g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error", 208 s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName, rc2)); 209 if (!g_aImports[i].fOptional) 210 { 211 if (RTErrInfoIsSet(pErrInfo)) 212 RTErrInfoAddF(pErrInfo, rc2, ", %s%s", 213 s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName); 214 else 215 rc = RTErrInfoSetF(pErrInfo, rc2, "Failed to import: %s%s", 216 s_pszDllPrefixes[g_aImports[i].idxDll], g_aImports[i].pszName); 217 Assert(RT_FAILURE(rc)); 218 } 219 } 220 } 221 if (RT_SUCCESS(rc)) 222 { 223 Assert(!RTErrInfoIsSet(pErrInfo)); 224 225 /* 226 * Check if the hypervisor API is present. 227 */ 228 /** @todo Someone (MS) please explain weird API design: 229 * 1. Caps.CapabilityCode duplication, 230 * 2. No output size. 231 */ 232 WHV_CAPABILITY Caps; 233 RT_ZERO(Caps); 234 SetLastError(0); 235 HRESULT hrc = WHvGetCapability(WHvCapabilityCodeHypervisorPresent, &Caps, sizeof(Caps)); 236 DWORD rcWin = GetLastError(); 237 if (FAILED(hrc)) 238 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, 239 "WHvGetCapability/WHvCapabilityCodeHypervisorPresent failed: %Rhrc", hrc); 240 else if (!Caps.HypervisorPresent) 241 { 242 if (!RTPathExists(RTPATH_NT_PASSTHRU_PREFIX "Device\\VidExo")) 243 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, 244 "WHvCapabilityCodeHypervisorPresent is FALSE! Make sure you have enabled the 'Windows Hypervisor Platform' feature."); 245 else 246 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_NOT_AVAILABLE, 247 "WHvCapabilityCodeHypervisorPresent is FALSE! (%u)", rcWin); 248 } 249 else 250 { 251 /* 252 * . 253 */ 254 LogRel(("NEM: WHvCapabilityCodeHypervisorPresent is TRUE, so this might work...\n")); 255 256 rc = RTErrInfoAddF(pErrInfo, VERR_NOT_IMPLEMENTED, "lazy bugger isn't done yet"); 257 } 258 } 259 RTLdrClose(ahMods[0]); 260 } 261 else 262 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, 263 "Failed to load API DLL 'WinHvPlatform.dll': %Rrc", rc); 264 RTLdrClose(ahMods[1]); 265 } 266 else 267 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Failed to load API DLL 'vid.dll': %Rrc", rc); 268 } 269 } 270 } 271 } 272 273 /* 274 * We only fail if in forced mode, otherwise just log the complaint and return. 275 */ 276 Assert(pVM->fNEMActive || RTErrInfoIsSet(pErrInfo)); 277 if ( (fForced || !fFallback) 278 && !pVM->fNEMActive) 279 return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s\n", pErrInfo->pszMsg); 280 281 if (RTErrInfoIsSet(pErrInfo)) 282 LogRel(("NEM: Not available: %s\n", pErrInfo->pszMsg)); 32 283 return VINF_SUCCESS; 33 284 }
Note:
See TracChangeset
for help on using the changeset viewer.