- Timestamp:
- Feb 9, 2018 11:45:56 PM (7 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/NEMR3.cpp
r70918 r70945 39 39 * 40 40 * @returns VBox status code. 41 * @param pVM The VM handle.41 * @param pVM The cross context VM structure. 42 42 */ 43 43 VMMR3_INT_DECL(int) NEMR3InitConfig(PVM pVM) … … 89 89 * 90 90 * @returns VBox status code. 91 * @param pVM The VM handle.91 * @param pVM The cross context VM structure. 92 92 * @param fFallback Whether this is a fallback call. Cleared if the VM is 93 93 * configured to use NEM instead of HM. … … 132 132 133 133 /** 134 * Perform initialization that depends on CPUM working. 135 * 136 * This is a noop if NEM wasn't activated by a previous NEMR3Init() call. 137 * 138 * @returns VBox status code. 139 * @param pVM The cross context VM structure. 140 */ 141 VMMR3_INT_DECL(int) NEMR3InitAfterCPUM(PVM pVM) 142 { 143 int rc = VINF_SUCCESS; 144 #ifdef VBOX_WITH_NATIVE_NEM 145 if (pVM->fNEMActive) 146 rc = nemR3NativeInitAfterCPUM(pVM); 147 #endif 148 return rc; 149 } 150 151 152 /** 134 153 * Called when a init phase has completed. 135 154 * 136 155 * @returns VBox status code. 137 * @param pVM 138 * @param enmWhat 156 * @param pVM The cross context VM structure. 157 * @param enmWhat The phase that completed. 139 158 */ 140 159 VMMR3_INT_DECL(int) NEMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat) … … 154 173 * 155 174 * @returns VBox status code. 156 * @param pVM The VM handle.175 * @param pVM The cross context VM structure. 157 176 */ 158 177 VMMR3_INT_DECL(int) NEMR3Term(PVM pVM) -
trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
r70944 r70945 131 131 * @param pErrInfo Where to always return error info. 132 132 */ 133 static int nemR3 NativeInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo)133 static int nemR3WinInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo) 134 134 { 135 135 #define NEM_LOG_REL_CAP_EX(a_szField, a_szFmt, a_Value) LogRel(("NEM: %-38s= " a_szFmt "\n", a_szField, a_Value)) … … 149 149 */ 150 150 /** 151 * @todo Someone (MS)please explain weird API design:152 * 1. Caps.CapabilityCode duplication,151 * @todo Someone at Microsoft please explain weird API design: 152 * 1. Pointless CapabilityCode duplication int the output; 153 153 * 2. No output size. 154 154 */ … … 287 287 return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "WHvGetCapability/WHvCapabilityCodeProcessorClFlushSize failed: %Rhrc", hrc); 288 288 NEM_LOG_REL_CAP_EX("WHvCapabilityCodeProcessorClFlushSize", "2^%u", Caps.ProcessorClFlushSize); 289 if (Caps.ProcessorClFlushSize < 8 && Caps.ProcessorClFlushSize > 9) 290 return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "Unsupported cache line flush size: %u", Caps.ProcessorClFlushSize); 291 pVM->nem.s.cCacheLineFlushShift = Caps.ProcessorClFlushSize; 289 292 290 293 /* … … 321 324 322 325 323 326 /** 327 * Creates and sets up a Hyper-V (exo) partition. 328 * 329 * @returns VBox status code. 330 * @param pVM The cross context VM structure. 331 * @param pErrInfo Where to always return error info. 332 */ 333 static int nemR3WinInitCreatePartition(PVM pVM, PRTERRINFO pErrInfo) 334 { 335 AssertReturn(!pVM->nem.s.hPartition, RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER, "Wrong initalization order")); 336 AssertReturn(!pVM->nem.s.hPartitionDevice, RTErrInfoSet(pErrInfo, VERR_WRONG_ORDER, "Wrong initalization order")); 337 338 /* 339 * Create the partition. 340 */ 341 WHV_PARTITION_HANDLE hPartition; 342 HRESULT hrc = WHvCreatePartition(&hPartition); 343 if (FAILED(hrc)) 344 return RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, "WHvCreatePartition failed with %Rhrc", hrc); 345 346 int rc; 347 348 /* 349 * Set partition properties, most importantly the CPU count. 350 */ 351 /** 352 * @todo Someone at microsoft please explain another weird API: 353 * - Why this API doesn't take the WHV_PARTITION_PROPERTY_CODE value as an 354 * argument rather than as part of the struct. That is so weird if you've 355 * used any other NT or windows API, including WHvGetCapability(). 356 * - Why use PVOID when WHV_PARTITION_PROPERTY is what's expected. We 357 * technically only need 9 bytes for setting/getting 358 * WHVPartitionPropertyCodeProcessorClFlushSize, but the API insists on 16. */ 359 WHV_PARTITION_PROPERTY Property; 360 RT_ZERO(Property); 361 Property.PropertyCode = WHvPartitionPropertyCodeProcessorCount; 362 Property.ProcessorCount = pVM->cCpus; 363 hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property)); 364 if (SUCCEEDED(hrc)) 365 { 366 RT_ZERO(Property); 367 Property.PropertyCode = WHvPartitionPropertyCodeExtendedVmExits; 368 Property.ExtendedVmExits.X64CpuidExit = pVM->nem.s.fExtendedCpuIdExit; 369 Property.ExtendedVmExits.X64MsrExit = pVM->nem.s.fExtendedMsrExit; 370 Property.ExtendedVmExits.ExceptionExit = pVM->nem.s.fExtendedXcptExit; 371 hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property)); 372 if (SUCCEEDED(hrc)) 373 { 374 /* 375 * We'll continue setup in nemR3NativeInitAfterCPUM. 376 */ 377 pVM->nem.s.fCreatedEmts = false; 378 pVM->nem.s.hPartition = hPartition; 379 LogRel(("NEM: Created partition %p.\n", hPartition)); 380 return VINF_SUCCESS; 381 } 382 383 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, 384 "Failed setting WHvPartitionPropertyCodeExtendedVmExits to %'#RX64: %Rhrc", 385 Property.ExtendedVmExits.AsUINT64, hrc); 386 } 387 else 388 rc = RTErrInfoSetF(pErrInfo, VERR_NEM_VM_CREATE_FAILED, 389 "Failed setting WHvPartitionPropertyCodeProcessorCount to %u: %Rhrc", pVM->cCpus, hrc); 390 WHvDeletePartition(hPartition); 391 392 Assert(!pVM->nem.s.hPartitionDevice); 393 Assert(!pVM->nem.s.hPartition); 394 return rc; 395 } 396 397 398 /** 399 * Try initialize the native API. 400 * 401 * This may only do part of the job, more can be done in 402 * nemR3NativeInitAfterCPUM() and nemR3NativeInitCompleted(). 403 * 404 * @returns VBox status code. 405 * @param pVM The cross context VM structure. 406 * @param fFallback Whether we're in fallback mode or use-NEM mode. In 407 * the latter we'll fail if we cannot initialize. 408 * @param fForced Whether the HMForced flag is set and we should 409 * fail if we cannot initialize. 410 */ 324 411 int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced) 325 412 { … … 425 512 * Check the capabilties of the hypervisor, starting with whether it's present. 426 513 */ 427 rc = nemR3 NativeInitCheckCapabilities(pVM, pErrInfo);514 rc = nemR3WinInitCheckCapabilities(pVM, pErrInfo); 428 515 if (RT_SUCCESS(rc)) 429 516 { 430 rc = RTErrInfoAddF(pErrInfo, VERR_NOT_IMPLEMENTED, "lazy bugger isn't done yet"); 517 /* 518 * Create and initialize a partition. 519 */ 520 rc = nemR3WinInitCreatePartition(pVM, pErrInfo); 521 if (RT_SUCCESS(rc)) 522 { 523 pVM->fNEMActive = true; 524 Log(("NEM: Marked active!\n")); 525 } 431 526 } 432 527 } … … 451 546 if ( (fForced || !fFallback) 452 547 && !pVM->fNEMActive) 453 return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s \n", pErrInfo->pszMsg);548 return VMSetError(pVM, RT_SUCCESS_NP(rc) ? VERR_NEM_NOT_AVAILABLE : rc, RT_SRC_POS, "%s", pErrInfo->pszMsg); 454 549 455 550 if (RTErrInfoIsSet(pErrInfo)) … … 459 554 460 555 556 /** 557 * This is called after CPUMR3Init is done. 558 * 559 * @returns VBox status code. 560 * @param pVM The VM handle.. 561 */ 562 int nemR3NativeInitAfterCPUM(PVM pVM) 563 { 564 /* 565 * Validate sanity. 566 */ 567 WHV_PARTITION_HANDLE hPartition = pVM->nem.s.hPartition; 568 AssertReturn(hPartition != NULL, VERR_WRONG_ORDER); 569 AssertReturn(!pVM->nem.s.hPartitionDevice, VERR_WRONG_ORDER); 570 AssertReturn(!pVM->nem.s.fCreatedEmts, VERR_WRONG_ORDER); 571 AssertReturn(!pVM->fNEMActive, VERR_WRONG_ORDER); 572 573 /* 574 * Continue setting up the partition now that we've got most of the CPUID feature stuff. 575 */ 576 577 /* Not sure if we really need to set the vendor. */ 578 WHV_PARTITION_PROPERTY Property; 579 RT_ZERO(Property); 580 Property.PropertyCode = WHvPartitionPropertyCodeProcessorVendor; 581 Property.ProcessorVendor = pVM->nem.s.enmCpuVendor == CPUMCPUVENDOR_AMD ? WHvProcessorVendorAmd 582 : WHvProcessorVendorIntel; 583 HRESULT hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property)); 584 if (FAILED(hrc)) 585 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, 586 "Failed to set WHvPartitionPropertyCodeProcessorVendor to %u: %Rhrc", Property.ProcessorVendor, hrc); 587 588 /* Not sure if we really need to set the cache line flush size. */ 589 RT_ZERO(Property); 590 Property.PropertyCode = WHvPartitionPropertyCodeProcessorClFlushSize; 591 Property.ProcessorClFlushSize = pVM->nem.s.cCacheLineFlushShift; 592 hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property)); 593 if (FAILED(hrc)) 594 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, 595 "Failed to set WHvPartitionPropertyCodeProcessorClFlushSize to %u: %Rhrc", 596 pVM->nem.s.cCacheLineFlushShift, hrc); 597 598 /* 599 * Sync CPU features with CPUM. 600 */ 601 /** @todo sync CPU features with CPUM. */ 602 603 /* Set the partition property. */ 604 RT_ZERO(Property); 605 Property.PropertyCode = WHvPartitionPropertyCodeProcessorFeatures; 606 Property.ProcessorFeatures.AsUINT64 = pVM->nem.s.uCpuFeatures.u64; 607 hrc = WHvSetPartitionProperty(hPartition, &Property, sizeof(Property)); 608 if (FAILED(hrc)) 609 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, 610 "Failed to set WHvPartitionPropertyCodeProcessorFeatures to %'#RX64: %Rhrc", 611 pVM->nem.s.uCpuFeatures.u64, hrc); 612 613 /* 614 * Set up the partition and create EMTs. 615 * 616 * Seems like this is where the partition is actually instantiated and we get 617 * a handle to it. 618 */ 619 hrc = WHvSetupPartition(hPartition); 620 if (FAILED(hrc)) 621 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Call to WHvSetupPartition failed: %Rhrc", hrc); 622 623 /* Get the handle. */ 624 HANDLE hPartitionDevice; 625 __try 626 { 627 hPartitionDevice = ((HANDLE *)hPartition)[1]; 628 } 629 __except(EXCEPTION_EXECUTE_HANDLER) 630 { 631 hrc = GetExceptionCode(); 632 hPartitionDevice = NULL; 633 } 634 if ( hPartitionDevice == NULL 635 || hPartitionDevice == (HANDLE)(intptr_t)-1) 636 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, 637 "Failed to get device handle for partition %p: %Rhrc", hPartition, hrc); 638 /** @todo Do a Vid query that uses the handle to check that we've got a 639 * working value. */ 640 pVM->nem.s.hPartitionDevice = hPartitionDevice; 641 642 /* 643 * Create EMTs. 644 */ 645 VMCPUID iCpu; 646 for (iCpu = 0; iCpu < pVM->cCpus; iCpu++) 647 { 648 hrc = WHvCreateVirtualProcessor(hPartition, iCpu, 0 /*fFlags*/); 649 if (FAILED(hrc)) 650 { 651 while (iCpu-- > 0) 652 { 653 HRESULT hrc2 = WHvDeleteVirtualProcessor(hPartition, iCpu); 654 AssertLogRelMsg(SUCCEEDED(hrc2), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc\n", hPartition, iCpu, hrc2)); 655 } 656 return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Call to WHvSetupPartition failed: %Rhrc", hrc); 657 } 658 } 659 pVM->nem.s.fCreatedEmts = true; 660 661 LogRel(("NEM: Successfully set up partition (device handle %p)\n", hPartitionDevice)); 662 return VINF_SUCCESS; 663 } 664 665 461 666 int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat) 462 667 { … … 468 673 int nemR3NativeTerm(PVM pVM) 469 674 { 470 NOREF(pVM); 675 /* 676 * Delete the partition. 677 */ 678 WHV_PARTITION_HANDLE hPartition = pVM->nem.s.hPartition; 679 pVM->nem.s.hPartition = NULL; 680 pVM->nem.s.hPartitionDevice = NULL; 681 if (hPartition != NULL) 682 { 683 VMCPUID iCpu = pVM->nem.s.fCreatedEmts ? pVM->cCpus : 0; 684 LogRel(("NEM: Destroying partition %p with its %u VCpus...\n", hPartition, iCpu)); 685 while (iCpu-- > 0) 686 { 687 HRESULT hrc = WHvDeleteVirtualProcessor(hPartition, iCpu); 688 AssertLogRelMsg(SUCCEEDED(hrc), ("WHvDeleteVirtualProcessor(%p, %u) -> %Rhrc\n", hPartition, iCpu, hrc)); 689 } 690 WHvDeletePartition(hPartition); 691 } 692 pVM->nem.s.fCreatedEmts = false; 471 693 return VINF_SUCCESS; 472 694 } -
trunk/src/VBox/VMM/VMMR3/VM.cpp
r70918 r70945 939 939 if (RT_SUCCESS(rc)) 940 940 { 941 rc = PGMR3Init(pVM); 941 rc = NEMR3InitAfterCPUM(pVM); 942 if (RT_SUCCESS(rc)) 943 rc = PGMR3Init(pVM); 942 944 if (RT_SUCCESS(rc)) 943 945 { -
trunk/src/VBox/VMM/include/NEMInternal.h
r70944 r70945 46 46 bool fEnabled; 47 47 #ifdef RT_OS_WINDOWS 48 /** Set if we've created the EMTs. */ 49 bool fCreatedEmts; 48 50 /** WHvRunVpExitReasonX64Cpuid is supported. */ 49 51 bool fExtendedMsrExit; … … 54 56 /** The reported CPU vendor. */ 55 57 CPUMCPUVENDOR enmCpuVendor; 56 /** Explicit padding. */57 uint 32_t u32Padding1;58 /** Cache line flush size as a power of two. */ 59 uint8_t cCacheLineFlushShift; 58 60 /** The result of WHvCapabilityCodeProcessorFeatures. */ 59 61 union … … 66 68 # endif 67 69 } uCpuFeatures; 70 71 /** The partition handle. */ 72 # ifdef _WINHVAPIDEFS_H_ 73 WHV_PARTITION_HANDLE 74 # else 75 RTHCUINTPTR 76 # endif 77 hPartition; 78 /** The device handle for the partition, for use with Vid APIs or direct I/O 79 * controls. */ 80 RTR3PTR hPartitionDevice; 68 81 #endif 69 82 … … 97 110 #ifdef IN_RING3 98 111 int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced); 112 int nemR3NativeInitAfterCPUM(PVM pVM); 99 113 int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); 100 114 int nemR3NativeTerm(PVM pVM);
Note:
See TracChangeset
for help on using the changeset viewer.