VirtualBox

Changeset 72300 in vbox for trunk/src/VBox/VMM/VMMR0


Ignore:
Timestamp:
May 23, 2018 3:13:06 PM (7 years ago)
Author:
vboxsync
Message:

NEM,STAM: Partition memory statistics for NEM. bugref:9044

  • STAM: Redid the way we handle statistics requiring fetching data from ring-0 (or elsewhere) by introducing a refresh group concept. We'll refresh the statistics for a group if needed and only once per enumeration/query. There's a new registration API for these.
  • NEM: Added memory balance statistics for the partition. Some failed fumbling thru VID.DLL/SYS, before realizing that hypercall is the only way to get at them.
  • NEM: Added a hypervisor input/output page buffer for non-EMT threads so we can get statistics. Put the related data and code into separate structure to save duplication.
Location:
trunk/src/VBox/VMM/VMMR0
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/NEMR0Native-win.cpp

    r72291 r72300  
    9090 */
    9191#include "../VMMAll/NEMAllNativeTemplate-win.cpp.h"
     92
     93/**
     94 * Worker for NEMR0InitVM that allocates a hypercall page.
     95 *
     96 * @returns VBox status code.
     97 * @param   pHypercallData  The hypercall data page to initialize.
     98 */
     99static int nemR0InitHypercallData(PNEMR0HYPERCALLDATA pHypercallData)
     100{
     101    int rc = RTR0MemObjAllocPage(&pHypercallData->hMemObj, PAGE_SIZE, false /*fExecutable*/);
     102    if (RT_SUCCESS(rc))
     103    {
     104        pHypercallData->HCPhysPage = RTR0MemObjGetPagePhysAddr(pHypercallData->hMemObj, 0 /*iPage*/);
     105        AssertStmt(pHypercallData->HCPhysPage != NIL_RTHCPHYS, rc = VERR_INTERNAL_ERROR_3);
     106        pHypercallData->pbPage     = (uint8_t *)RTR0MemObjAddress(pHypercallData->hMemObj);
     107        AssertStmt(pHypercallData->pbPage, rc = VERR_INTERNAL_ERROR_3);
     108        if (RT_SUCCESS(rc))
     109            return VINF_SUCCESS;
     110
     111        /* bail out */
     112        RTR0MemObjFree(pHypercallData->hMemObj, true /*fFreeMappings*/);
     113    }
     114    pHypercallData->hMemObj     = NIL_RTR0MEMOBJ;
     115    pHypercallData->HCPhysPage  = NIL_RTHCPHYS;
     116    pHypercallData->pbPage      = NULL;
     117    return rc;
     118}
     119
     120/**
     121 * Worker for NEMR0CleanupVM and NEMR0InitVM that cleans up a hypercall page.
     122 *
     123 * @param   pHypercallData  The hypercall data page to uninitialize.
     124 */
     125static void nemR0DeleteHypercallData(PNEMR0HYPERCALLDATA pHypercallData)
     126{
     127    /* Check pbPage here since it's NULL, whereas the hMemObj can be either
     128       NIL_RTR0MEMOBJ or 0 (they aren't necessarily the same). */
     129    if (pHypercallData->pbPage != NULL)
     130    {
     131        RTR0MemObjFree(pHypercallData->hMemObj, true /*fFreeMappings*/);
     132        pHypercallData->pbPage = NULL;
     133    }
     134    pHypercallData->hMemObj    = NIL_RTR0MEMOBJ;
     135    pHypercallData->HCPhysPage = NIL_RTHCPHYS;
     136}
    92137
    93138
     
    127172        {
    128173            /*
    129              * Allocate a page for each VCPU to place hypercall data on.
     174             * Allocate a page for non-EMT threads to use for hypercalls (update
     175             * statistics and such) and a critical section protecting it.
    130176             */
    131             for (VMCPUID i = 0; i < pGVM->cCpus; i++)
     177            rc = RTCritSectInit(&pGVM->nem.s.HypercallDataCritSect);
     178            if (RT_SUCCESS(rc))
    132179            {
    133                 PGVMCPU pGVCpu = &pGVM->aCpus[i];
    134                 rc = RTR0MemObjAllocPage(&pGVCpu->nem.s.hHypercallDataMemObj, PAGE_SIZE, false /*fExecutable*/);
     180                rc = nemR0InitHypercallData(&pGVM->nem.s.HypercallData);
    135181                if (RT_SUCCESS(rc))
    136182                {
    137                     pGVCpu->nem.s.HCPhysHypercallData = RTR0MemObjGetPagePhysAddr(pGVCpu->nem.s.hHypercallDataMemObj, 0 /*iPage*/);
    138                     pGVCpu->nem.s.pbHypercallData     = (uint8_t *)RTR0MemObjAddress(pGVCpu->nem.s.hHypercallDataMemObj);
    139                     AssertStmt(pGVCpu->nem.s.HCPhysHypercallData != NIL_RTHCPHYS, rc = VERR_INTERNAL_ERROR_3);
    140                     AssertStmt(pGVCpu->nem.s.pbHypercallData, rc = VERR_INTERNAL_ERROR_3);
     183                    /*
     184                     * Allocate a page for each VCPU to place hypercall data on.
     185                     */
     186                    for (VMCPUID i = 0; i < pGVM->cCpus; i++)
     187                    {
     188                        rc = nemR0InitHypercallData(&pGVM->aCpus[i].nem.s.HypercallData);
     189                        if (RT_FAILURE(rc))
     190                        {
     191                            while (i-- > 0)
     192                                nemR0DeleteHypercallData(&pGVM->aCpus[i].nem.s.HypercallData);
     193                            break;
     194                        }
     195                    }
     196                    if (RT_SUCCESS(rc))
     197                    {
     198                        /*
     199                         * So far, so good.
     200                         */
     201                        return rc;
     202                    }
     203
     204                    /*
     205                     * Bail out.
     206                     */
     207                    nemR0DeleteHypercallData(&pGVM->nem.s.HypercallData);
    141208                }
    142                 else
    143                     pGVCpu->nem.s.hHypercallDataMemObj = NIL_RTR0MEMOBJ;
    144                 if (RT_FAILURE(rc))
    145                 {
    146                     /* bail. */
    147                     do
    148                     {
    149                         RTR0MemObjFree(pGVCpu->nem.s.hHypercallDataMemObj, true /*fFreeMappings*/);
    150                         pGVCpu->nem.s.hHypercallDataMemObj = NIL_RTR0MEMOBJ;
    151                         pGVCpu->nem.s.HCPhysHypercallData  = NIL_RTHCPHYS;
    152                         pGVCpu->nem.s.pbHypercallData      = NULL;
    153                     } while (i-- > 0);
    154                     return rc;
    155                 }
     209                RTCritSectDelete(&pGVM->nem.s.HypercallDataCritSect);
    156210            }
    157             /*
    158              * So far, so good.
    159              */
    160             return rc;
    161         }
    162 
    163         rc = VERR_NEM_MISSING_KERNEL_API;
    164     }
    165 
    166     RT_NOREF(pGVM, pVM);
     211        }
     212        else
     213            rc = VERR_NEM_MISSING_KERNEL_API;
     214    }
     215
     216    RT_NOREF(pVM);
    167217    return rc;
    168218}
     
    309359    VMCPUID i = pGVM->cCpus;
    310360    while (i-- > 0)
    311     {
    312         PGVMCPU pGVCpu = &pGVM->aCpus[i];
    313         if (pGVCpu->nem.s.pbHypercallData)
    314         {
    315             pGVCpu->nem.s.pbHypercallData = NULL;
    316             int rc = RTR0MemObjFree(pGVCpu->nem.s.hHypercallDataMemObj, true /*fFreeMappings*/);
    317             AssertRC(rc);
    318         }
    319         pGVCpu->nem.s.hHypercallDataMemObj = NIL_RTR0MEMOBJ;
    320         pGVCpu->nem.s.HCPhysHypercallData  = NIL_RTHCPHYS;
    321     }
     361        nemR0DeleteHypercallData(&pGVM->aCpus[i].nem.s.HypercallData);
     362
     363    /* The non-EMT one too. */
     364    if (RTCritSectIsInitialized(&pGVM->nem.s.HypercallDataCritSect))
     365        RTCritSectDelete(&pGVM->nem.s.HypercallDataCritSect);
     366    nemR0DeleteHypercallData(&pGVM->nem.s.HypercallData);
    322367}
    323368
     
    372417     * Ring-3 is not allowed to fill in the host physical addresses of the call.
    373418     */
    374     HV_INPUT_MAP_GPA_PAGES *pMapPages = (HV_INPUT_MAP_GPA_PAGES *)pGVCpu->nem.s.pbHypercallData;
     419    HV_INPUT_MAP_GPA_PAGES *pMapPages = (HV_INPUT_MAP_GPA_PAGES *)pGVCpu->nem.s.HypercallData.pbPage;
    375420    AssertPtrReturn(pMapPages, VERR_INTERNAL_ERROR_3);
    376421    pMapPages->TargetPartitionId    = pGVM->nem.s.idHvPartition;
     
    387432
    388433    uint64_t uResult = g_pfnHvlInvokeHypercall(HvCallMapGpaPages | ((uint64_t)cPages << 32),
    389                                                pGVCpu->nem.s.HCPhysHypercallData, 0);
     434                                               pGVCpu->nem.s.HypercallData.HCPhysPage, 0);
    390435    Log6(("NEMR0MapPages: %RGp/%RGp L %u prot %#x -> %#RX64\n",
    391436          GCPhysDst, GCPhysSrc - cPages * X86_PAGE_SIZE, cPages, fFlags, uResult));
     
    454499     * Compose and make the hypercall.
    455500     */
    456     HV_INPUT_UNMAP_GPA_PAGES *pUnmapPages = (HV_INPUT_UNMAP_GPA_PAGES *)pGVCpu->nem.s.pbHypercallData;
     501    HV_INPUT_UNMAP_GPA_PAGES *pUnmapPages = (HV_INPUT_UNMAP_GPA_PAGES *)pGVCpu->nem.s.HypercallData.pbPage;
    457502    AssertPtrReturn(pUnmapPages, VERR_INTERNAL_ERROR_3);
    458503    pUnmapPages->TargetPartitionId    = pGVM->nem.s.idHvPartition;
     
    461506
    462507    uint64_t uResult = g_pfnHvlInvokeHypercall(HvCallUnmapGpaPages | ((uint64_t)cPages << 32),
    463                                                pGVCpu->nem.s.HCPhysHypercallData, 0);
     508                                               pGVCpu->nem.s.HypercallData.HCPhysPage, 0);
    464509    Log6(("NEMR0UnmapPages: %RGp L %u -> %#RX64\n", GCPhys, cPages, uResult));
    465510    if (uResult == ((uint64_t)cPages << 32))
     
    467512#if 1       /* Do we need to do this? Hopefully not... */
    468513        uint64_t volatile uR = g_pfnHvlInvokeHypercall(HvCallUncommitGpaPages | ((uint64_t)cPages << 32),
    469                                                        pGVCpu->nem.s.HCPhysHypercallData, 0);
     514                                                       pGVCpu->nem.s.HypercallData.HCPhysPage, 0);
    470515        AssertMsg(uR == ((uint64_t)cPages << 32), ("uR=%#RX64\n", uR)); NOREF(uR);
    471516#endif
     
    527572{
    528573    PVMCPU                     pVCpu  = &pGVM->pVM->aCpus[pGVCpu->idCpu];
    529     HV_INPUT_SET_VP_REGISTERS *pInput = (HV_INPUT_SET_VP_REGISTERS *)pGVCpu->nem.s.pbHypercallData;
     574    HV_INPUT_SET_VP_REGISTERS *pInput = (HV_INPUT_SET_VP_REGISTERS *)pGVCpu->nem.s.HypercallData.pbPage;
    530575    AssertPtrReturn(pInput, VERR_INTERNAL_ERROR_3);
    531576
     
    10961141     * Set the registers.
    10971142     */
    1098     Assert((uintptr_t)&pInput->Elements[iReg] - (uintptr_t)pGVCpu->nem.s.pbHypercallData < PAGE_SIZE); /* max is 127 */
     1143    Assert((uintptr_t)&pInput->Elements[iReg] - (uintptr_t)pGVCpu->nem.s.HypercallData.pbPage < PAGE_SIZE); /* max is 127 */
    10991144
    11001145    /*
     
    11021147     */
    11031148    uint64_t uResult = g_pfnHvlInvokeHypercall(HV_MAKE_CALL_INFO(HvCallSetVpRegisters, iReg),
    1104                                                pGVCpu->nem.s.HCPhysHypercallData, 0 /*GCPhysOutput*/);
     1149                                               pGVCpu->nem.s.HypercallData.HCPhysPage, 0 /*GCPhysOutput*/);
    11051150    AssertLogRelMsgReturn(uResult == HV_MAKE_CALL_REP_RET(iReg),
    11061151                          ("uResult=%RX64 iRegs=%#x\n", uResult, iReg),
     
    11561201NEM_TMPL_STATIC int nemR0WinImportState(PGVM pGVM, PGVMCPU pGVCpu, PCPUMCTX pCtx, uint64_t fWhat)
    11571202{
    1158     HV_INPUT_GET_VP_REGISTERS *pInput = (HV_INPUT_GET_VP_REGISTERS *)pGVCpu->nem.s.pbHypercallData;
     1203    HV_INPUT_GET_VP_REGISTERS *pInput = (HV_INPUT_GET_VP_REGISTERS *)pGVCpu->nem.s.HypercallData.pbPage;
    11591204    AssertPtrReturn(pInput, VERR_INTERNAL_ERROR_3);
    11601205
     
    13391384
    13401385    HV_REGISTER_VALUE *paValues = (HV_REGISTER_VALUE *)((uint8_t *)pInput + cbInput);
    1341     Assert((uintptr_t)&paValues[cRegs] - (uintptr_t)pGVCpu->nem.s.pbHypercallData < PAGE_SIZE); /* (max is around 168 registers) */
     1386    Assert((uintptr_t)&paValues[cRegs] - (uintptr_t)pGVCpu->nem.s.HypercallData.pbPage < PAGE_SIZE); /* (max is around 168 registers) */
    13421387    RT_BZERO(paValues, cRegs * sizeof(paValues[0]));
    13431388
     
    13461391     */
    13471392    uint64_t uResult = g_pfnHvlInvokeHypercall(HV_MAKE_CALL_INFO(HvCallGetVpRegisters, cRegs),
    1348                                                pGVCpu->nem.s.HCPhysHypercallData,
    1349                                                pGVCpu->nem.s.HCPhysHypercallData + cbInput);
     1393                                               pGVCpu->nem.s.HypercallData.HCPhysPage,
     1394                                               pGVCpu->nem.s.HypercallData.HCPhysPage + cbInput);
    13501395    AssertLogRelMsgReturn(uResult == HV_MAKE_CALL_REP_RET(cRegs),
    13511396                          ("uResult=%RX64 cRegs=%#x\n", uResult, cRegs),
     
    18931938}
    18941939
     1940
     1941/**
     1942 * Updates statistics in the VM structure.
     1943 *
     1944 * @returns VBox status code.
     1945 * @param   pGVM        The ring-0 VM handle.
     1946 * @param   pVM         The cross context VM handle.
     1947 * @param   idCpu       The calling EMT, or NIL.  Necessary for getting the hypercall
     1948 *                      page and arguments.
     1949 */
     1950VMMR0_INT_DECL(int)  NEMR0UpdateStatistics(PGVM pGVM, PVM pVM, VMCPUID idCpu)
     1951{
     1952    /*
     1953     * Validate the call.
     1954     */
     1955    int rc;
     1956    if (idCpu == NIL_VMCPUID)
     1957        rc = GVMMR0ValidateGVMandVM(pGVM, pVM);
     1958    else
     1959        rc = GVMMR0ValidateGVMandVMandEMT(pGVM, pVM, idCpu);
     1960    if (RT_SUCCESS(rc))
     1961    {
     1962        AssertReturn(g_pfnHvlInvokeHypercall, VERR_NEM_MISSING_KERNEL_API);
     1963
     1964        PNEMR0HYPERCALLDATA pHypercallData = idCpu != NIL_VMCPUID
     1965                                           ? &pGVM->aCpus[idCpu].nem.s.HypercallData
     1966                                           : &pGVM->nem.s.HypercallData;
     1967        if (   RT_VALID_PTR(pHypercallData->pbPage)
     1968            && pHypercallData->HCPhysPage != NIL_RTHCPHYS)
     1969        {
     1970            if (idCpu == NIL_VMCPUID)
     1971                rc = RTCritSectEnter(&pGVM->nem.s.HypercallDataCritSect);
     1972            if (RT_SUCCESS(rc))
     1973            {
     1974                /*
     1975                 * Query the memory statistics for the partition.
     1976                 */
     1977                HV_INPUT_GET_MEMORY_BALANCE  *pInput = (HV_INPUT_GET_MEMORY_BALANCE *)pHypercallData->pbPage;
     1978                pInput->TargetPartitionId                               = pGVM->nem.s.idHvPartition;
     1979                pInput->ProximityDomainInfo.Flags.ProximityPreferred    = 0;
     1980                pInput->ProximityDomainInfo.Flags.ProxyimityInfoValid   = 0;
     1981                pInput->ProximityDomainInfo.Flags.Reserved              = 0;
     1982                pInput->ProximityDomainInfo.Id                          = 0;
     1983
     1984                HV_OUTPUT_GET_MEMORY_BALANCE *pOutput = (HV_OUTPUT_GET_MEMORY_BALANCE *)(pInput + 1);
     1985                RT_ZERO(*pOutput);
     1986
     1987                uint64_t uResult = g_pfnHvlInvokeHypercall(HvCallGetMemoryBalance,
     1988                                                           pHypercallData->HCPhysPage,
     1989                                                           pHypercallData->HCPhysPage + sizeof(*pInput));
     1990                if (uResult == HV_STATUS_SUCCESS)
     1991                {
     1992                    pVM->nem.s.R0Stats.cPagesAvailable = pOutput->PagesAvailable;
     1993                    pVM->nem.s.R0Stats.cPagesInUse     = pOutput->PagesInUse;
     1994                    rc = VINF_SUCCESS;
     1995                }
     1996                else
     1997                {
     1998                    LogRel(("HvCallGetMemoryBalance -> %#RX64 (%#RX64 %#RX64)!!\n",
     1999                            uResult, pOutput->PagesAvailable, pOutput->PagesInUse));
     2000                    rc = VINF_NEM_IPE_0;
     2001                }
     2002
     2003                if (idCpu == NIL_VMCPUID)
     2004                    RTCritSectLeave(&pGVM->nem.s.HypercallDataCritSect);
     2005            }
     2006        }
     2007        else
     2008            rc = VERR_WRONG_ORDER;
     2009    }
     2010    return rc;
     2011}
     2012
  • trunk/src/VBox/VMM/VMMR0/VMMR0.cpp

    r71223 r72300  
    20622062            VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
    20632063            break;
     2064
     2065        case VMMR0_DO_NEM_UPDATE_STATISTICS:
     2066            if (u64Arg || pReqHdr)
     2067                return VERR_INVALID_PARAMETER;
     2068            rc = NEMR0UpdateStatistics(pGVM, pVM, idCpu);
     2069            VMM_CHECK_SMAP_CHECK2(pVM, RT_NOTHING);
     2070            break;
    20642071# endif
    20652072#endif
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