VirtualBox

Changeset 70945 in vbox for trunk


Ignore:
Timestamp:
Feb 9, 2018 11:45:56 PM (7 years ago)
Author:
vboxsync
Message:

VMM/NEM: More code.

Location:
trunk/src/VBox/VMM
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/NEMR3.cpp

    r70918 r70945  
    3939 *
    4040 * @returns VBox status code.
    41  * @param   pVM         The VM handle.
     41 * @param   pVM         The cross context VM structure.
    4242 */
    4343VMMR3_INT_DECL(int) NEMR3InitConfig(PVM pVM)
     
    8989 *
    9090 * @returns VBox status code.
    91  * @param   pVM         The VM handle.
     91 * @param   pVM         The cross context VM structure.
    9292 * @param   fFallback   Whether this is a fallback call.  Cleared if the VM is
    9393 *                      configured to use NEM instead of HM.
     
    132132
    133133/**
     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 */
     141VMMR3_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/**
    134153 * Called when a init phase has completed.
    135154 *
    136155 * @returns VBox status code.
    137  * @param   pVM                 The cross context VM structure.
    138  * @param   enmWhat             The phase that completed.
     156 * @param   pVM         The cross context VM structure.
     157 * @param   enmWhat     The phase that completed.
    139158 */
    140159VMMR3_INT_DECL(int) NEMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
     
    154173 *
    155174 * @returns VBox status code.
    156  * @param   pVM         The VM handle.
     175 * @param   pVM         The cross context VM structure.
    157176 */
    158177VMMR3_INT_DECL(int) NEMR3Term(PVM pVM)
  • trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp

    r70944 r70945  
    131131 * @param   pErrInfo            Where to always return error info.
    132132 */
    133 static int nemR3NativeInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo)
     133static int nemR3WinInitCheckCapabilities(PVM pVM, PRTERRINFO pErrInfo)
    134134{
    135135#define NEM_LOG_REL_CAP_EX(a_szField, a_szFmt, a_Value)     LogRel(("NEM: %-38s= " a_szFmt "\n", a_szField, a_Value))
     
    149149     */
    150150    /**
    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;
    153153     *   2. No output size.
    154154     */
     
    287287        return RTErrInfoSetF(pErrInfo, VERR_NEM_INIT_FAILED, "WHvGetCapability/WHvCapabilityCodeProcessorClFlushSize failed: %Rhrc", hrc);
    288288    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;
    289292
    290293    /*
     
    321324
    322325
    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 */
     333static 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 */
    324411int nemR3NativeInit(PVM pVM, bool fFallback, bool fForced)
    325412{
     
    425512                                 * Check the capabilties of the hypervisor, starting with whether it's present.
    426513                                 */
    427                                 rc = nemR3NativeInitCheckCapabilities(pVM, pErrInfo);
     514                                rc = nemR3WinInitCheckCapabilities(pVM, pErrInfo);
    428515                                if (RT_SUCCESS(rc))
    429516                                {
    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                                    }
    431526                                }
    432527                            }
     
    451546    if (   (fForced || !fFallback)
    452547        && !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);
    454549
    455550    if (RTErrInfoIsSet(pErrInfo))
     
    459554
    460555
     556/**
     557 * This is called after CPUMR3Init is done.
     558 *
     559 * @returns VBox status code.
     560 * @param   pVM                 The VM handle..
     561 */
     562int 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
    461666int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
    462667{
     
    468673int nemR3NativeTerm(PVM pVM)
    469674{
    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;
    471693    return VINF_SUCCESS;
    472694}
  • trunk/src/VBox/VMM/VMMR3/VM.cpp

    r70918 r70945  
    939939            if (RT_SUCCESS(rc))
    940940            {
    941                 rc = PGMR3Init(pVM);
     941                rc = NEMR3InitAfterCPUM(pVM);
     942                if (RT_SUCCESS(rc))
     943                    rc = PGMR3Init(pVM);
    942944                if (RT_SUCCESS(rc))
    943945                {
  • trunk/src/VBox/VMM/include/NEMInternal.h

    r70944 r70945  
    4646    bool                        fEnabled;
    4747#ifdef RT_OS_WINDOWS
     48    /** Set if we've created the EMTs. */
     49    bool                        fCreatedEmts;
    4850    /** WHvRunVpExitReasonX64Cpuid is supported. */
    4951    bool                        fExtendedMsrExit;
     
    5456    /** The reported CPU vendor.   */
    5557    CPUMCPUVENDOR               enmCpuVendor;
    56     /** Explicit padding. */
    57     uint32_t                    u32Padding1;
     58    /** Cache line flush size as a power of two. */
     59    uint8_t                     cCacheLineFlushShift;
    5860    /** The result of WHvCapabilityCodeProcessorFeatures. */
    5961    union
     
    6668# endif
    6769    } 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;
    6881#endif
    6982
     
    97110#ifdef IN_RING3
    98111int     nemR3NativeInit(PVM pVM, bool fFallback, bool fForced);
     112int     nemR3NativeInitAfterCPUM(PVM pVM);
    99113int     nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
    100114int     nemR3NativeTerm(PVM pVM);
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