GVMMR0.cpp revision bb3918f6c6bdb4e45c58cb78e8f1f286c94ac933
42576743851c3c956ad7e867e74df1084c30d434vboxsync * GVMM - Global VM Manager.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * Copyright (C) 2007 innotek GmbH
42576743851c3c956ad7e867e74df1084c30d434vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
42576743851c3c956ad7e867e74df1084c30d434vboxsync * available from http://www.virtualbox.org. This file is free software;
42576743851c3c956ad7e867e74df1084c30d434vboxsync * you can redistribute it and/or modify it under the terms of the GNU
42576743851c3c956ad7e867e74df1084c30d434vboxsync * General Public License (GPL) as published by the Free Software
42576743851c3c956ad7e867e74df1084c30d434vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
42576743851c3c956ad7e867e74df1084c30d434vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
42576743851c3c956ad7e867e74df1084c30d434vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
42576743851c3c956ad7e867e74df1084c30d434vboxsync/** @page pg_GVMM GVMM - The Global VM Manager
42576743851c3c956ad7e867e74df1084c30d434vboxsync * The Global VM Manager lives in ring-0. It's main function at the moment
42576743851c3c956ad7e867e74df1084c30d434vboxsync * is to manage a list of all running VMs, keep a ring-0 only structure (GVM)
42576743851c3c956ad7e867e74df1084c30d434vboxsync * for each of them, and assign them unique identifiers (so GMM can track
42576743851c3c956ad7e867e74df1084c30d434vboxsync * page owners). The idea for the future is to add an idle priority kernel
42576743851c3c956ad7e867e74df1084c30d434vboxsync * thread that can take care of tasks like page sharing.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * The GVMM will create a ring-0 object for each VM when it's registered,
42576743851c3c956ad7e867e74df1084c30d434vboxsync * this is both for session cleanup purposes and for having a point where
42576743851c3c956ad7e867e74df1084c30d434vboxsync * it's possible to implement usage polices later (in SUPR0ObjRegister).
42576743851c3c956ad7e867e74df1084c30d434vboxsync/*******************************************************************************
42576743851c3c956ad7e867e74df1084c30d434vboxsync* Header Files *
6998b7cea7c904f33047cd17b05bea760a5839a9vboxsync*******************************************************************************/
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync/*******************************************************************************
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync* Structures and Typedefs *
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync*******************************************************************************/
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync * Global VM handle.
99a5f7beff5f7bbf1f73923087d60070ddb717d4vboxsynctypedef struct GVMHANDLE
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync /** The index of the next handle in the list (free or used). (0 is nil.) */
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync /** Our own index / handle value. */
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync /** The pointer to the ring-0 only (aka global) VM structure. */
c6b3d55ef646614cc689faa1fa4ddc961712b6ffvboxsync /** The ring-0 mapping of the shared VM instance data. */
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync /** The virtual machine object. */
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync /** The session this VM is associated with. */
42576743851c3c956ad7e867e74df1084c30d434vboxsync /** The ring-0 handle of the EMT thread.
99a5f7beff5f7bbf1f73923087d60070ddb717d4vboxsync * This is used for assertions and similar cases where we need to find the VM handle. */
99a5f7beff5f7bbf1f73923087d60070ddb717d4vboxsync/** Pointer to a global VM handle. */
99a5f7beff5f7bbf1f73923087d60070ddb717d4vboxsync * The GVMM instance data.
43bc5c863e4a7f97ef53171421559ea863af4b11vboxsynctypedef struct GVMM
02f73b88a6e96b7f1b8ab0bbb98cfb798b566fbdvboxsync /** Eyecatcher / magic. */
02f73b88a6e96b7f1b8ab0bbb98cfb798b566fbdvboxsync /** The index of the head of the free handle chain. (0 is nil.) */
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync /** The index of the head of the active handle chain. (0 is nil.) */
43d42414bba4afb4e2aa2565d9278a3194f09304vboxsync /** The number of VMs. */
43d42414bba4afb4e2aa2565d9278a3194f09304vboxsync// /** The number of halted EMT threads. */
43d42414bba4afb4e2aa2565d9278a3194f09304vboxsync// uint16_t volatile cHaltedEMTs;
43d42414bba4afb4e2aa2565d9278a3194f09304vboxsync /** The lock used to serialize VM creation, destruction and associated events that
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * isn't performance critical. Owners may acquire the list lock. */
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync /** The lock used to serialize used list updates and accesses.
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * This indirectly includes scheduling since the scheduler will have to walk the
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * used list to examin running VMs. Owners may not acquire any other locks. */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /** The handle array.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * The size of this array defines the maximum number of currently running VMs.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * The first entry is unused as it represents the NIL handle. */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /** @gcfgm{/GVMM/cVMsMeansCompany, 32-bit, 0, UINT32_MAX, 1}
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * The number of VMs that means we no longer consider ourselves alone on a CPU/Core.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /** @gcfgm{/GVMM/MinSleepAlone,32-bit, 0, 100000000, 750000, ns}
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * The minimum sleep time for when we're alone, in nano seconds.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /** @gcfgm{/GVMM/MinSleepCompany,32-bit,0, 100000000, 15000, ns}
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * The minimum sleep time for when we've got company, in nano seconds.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /** @gcfgm{/GVMM/EarlyWakeUp1, 32-bit, 0, 100000000, 25000, ns}
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * The limit for the first round of early wakeups, given in nano seconds.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /** @gcfgm{/GVMM/EarlyWakeUp2, 32-bit, 0, 100000000, 50000, ns}
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * The limit for the second round of early wakeups, given in nano seconds.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync/** Pointer to the GVMM instance data. */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync/** The GVMM::u32Magic value (Charlie Haden). */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync/*******************************************************************************
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync* Global Variables *
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync*******************************************************************************/
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync/** Pointer to the GVMM instance data.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * (Just my general dislike for global variables.) */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync/** Macro for obtaining and validating the g_pGVMM pointer.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * On failure it will return from the invoking function with the specified return value.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pGVMM The name of the pGVMM variable.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param rc The return value on failure. Use VERR_INTERNAL_ERROR for
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync * VBox status codes.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync AssertMsgReturn((pGVMM)->u32Magic == GVMM_MAGIC, ("%p - %#x\n", (pGVMM), (pGVMM)->u32Magic), (rc)); \
1379dfd407ada5fab15655776896f13b61a951fdvboxsync } while (0)
1379dfd407ada5fab15655776896f13b61a951fdvboxsync/** Macro for obtaining and validating the g_pGVMM pointer, void function variant.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * On failure it will return from the invoking function.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param pGVMM The name of the pGVMM variable.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync AssertMsgReturnVoid((pGVMM)->u32Magic == GVMM_MAGIC, ("%p - %#x\n", (pGVMM), (pGVMM)->u32Magic)); \
1379dfd407ada5fab15655776896f13b61a951fdvboxsync } while (0)
1379dfd407ada5fab15655776896f13b61a951fdvboxsync/*******************************************************************************
1379dfd407ada5fab15655776896f13b61a951fdvboxsync* Internal Functions *
1379dfd407ada5fab15655776896f13b61a951fdvboxsync*******************************************************************************/
1379dfd407ada5fab15655776896f13b61a951fdvboxsyncstatic DECLCALLBACK(void) gvmmR0HandleObjDestructor(void *pvObj, void *pvGVMM, void *pvHandle);
1379dfd407ada5fab15655776896f13b61a951fdvboxsyncstatic int gvmmR0ByVM(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM, bool fTakeUsedLock);
1379dfd407ada5fab15655776896f13b61a951fdvboxsyncstatic int gvmmR0ByVMAndEMT(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM);
42576743851c3c956ad7e867e74df1084c30d434vboxsync * Initializes the GVMM.
cb70b5cc08e3b666361766188f99cc86ed1626fbvboxsync * This is called while owninng the loader sempahore (see supdrvIOCtl_LdrLoad()).
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync * @returns VBox status code.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * Allocate and initialize the instance data.
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsync int rc = RTSemFastMutexCreate(&pGVMM->CreateDestroyLock);
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsync /* the nil handle */
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /* the tail */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /* the rest */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync while (i-- > 1)
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /* The default configuration values. */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync pGVMM->cVMsMeansCompany = 1; /** @todo should be adjusted to relative to the cpu count or something... */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync pGVMM->nsMinSleepAlone = 750000 /* ns (0.750 ms) */; /** @todo this should be adjusted to be 75% (or something) of the scheduler granularity... */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync pGVMM->nsMinSleepCompany = 15000 /* ns (0.015 ms) */;
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * Terminates the GVM.
02f73b88a6e96b7f1b8ab0bbb98cfb798b566fbdvboxsync * This is called while owning the loader semaphore (see supdrvLdrFree()).
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * And unless something is wrong, there should be absolutely no VMs
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * registered at this point.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync SUPR0Printf("GVMMR0Term: iUsedHead=%#x! (cVMs=%#x)\n", pGVMM->iUsedHead, pGVMM->cVMs);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * A quick hack for setting global config values.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @returns VBox status code.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @param pSession The session handle. Used for authentication.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @param pszName The variable name.
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * @param u64Value The new value.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsyncGVMMR0DECL(int) GVMMR0SetConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t u64Value)
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync * Validate input.
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync GVMM_GET_VALID_INSTANCE(pGVMM, VERR_INTERNAL_ERROR);
b32be08cd134577ca98e517c019c867c416ec0f2vboxsync * String switch time!
f4d2071f8959189ae2c0c2faa4d2944ee37523d9vboxsync if (strncmp(pszName, "/GVMM/", sizeof("/GVMM/") - 1))
81614fc60e096e714022d10d38b70a36b9b21d48vboxsync return VERR_CFGM_VALUE_NOT_FOUND; /* borrow status codes from CFGM... */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * A quick hack for getting global config values.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @returns VBox status code.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pSession The session handle. Used for authentication.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pszName The variable name.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param u64Value The new value.
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsyncGVMMR0DECL(int) GVMMR0QueryConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t *pu64Value)
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Validate input.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync GVMM_GET_VALID_INSTANCE(pGVMM, VERR_INTERNAL_ERROR);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * String switch time!
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync if (strncmp(pszName, "/GVMM/", sizeof("/GVMM/") - 1))
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync return VERR_CFGM_VALUE_NOT_FOUND; /* borrow status codes from CFGM... */
6998b7cea7c904f33047cd17b05bea760a5839a9vboxsync * Try acquire the 'used' lock.
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * @returns IPRT status code, see RTSemFastMutexRequest.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pGVMM The GVMM instance data.
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync LogFlow(("gvmmR0UsedLock(%p)->%Rrc\n", pGVMM, rc));
42576743851c3c956ad7e867e74df1084c30d434vboxsync * Release the 'used' lock.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @returns IPRT status code, see RTSemFastMutexRelease.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pGVMM The GVMM instance data.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Try acquire the 'create & destroy' lock.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @returns IPRT status code, see RTSemFastMutexRequest.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pGVMM The GVMM instance data.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsyncDECLINLINE(int) gvmmR0CreateDestroyLock(PGVMM pGVMM)
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync LogFlow(("++gvmmR0CreateDestroyLock(%p)\n", pGVMM));
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync int rc = RTSemFastMutexRequest(pGVMM->CreateDestroyLock);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync LogFlow(("gvmmR0CreateDestroyLock(%p)->%Rrc\n", pGVMM, rc));
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Release the 'create & destroy' lock.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @returns IPRT status code, see RTSemFastMutexRequest.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pGVMM The GVMM instance data.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsyncDECLINLINE(int) gvmmR0CreateDestroyUnlock(PGVMM pGVMM)
b32be08cd134577ca98e517c019c867c416ec0f2vboxsync LogFlow(("--gvmmR0CreateDestroyUnlock(%p)\n", pGVMM));
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync int rc = RTSemFastMutexRelease(pGVMM->CreateDestroyLock);
42576743851c3c956ad7e867e74df1084c30d434vboxsync * Request wrapper for the GVMMR0CreateVM API.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @returns VBox status code.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @param pReq The request buffer.
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsyncGVMMR0DECL(int) GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq)
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync * Validate the request.
b32be08cd134577ca98e517c019c867c416ec0f2vboxsync * Execute it.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Allocates the VM structure and registers it with GVM.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * The caller will become the VM owner and there by the EMT.
b32be08cd134577ca98e517c019c867c416ec0f2vboxsync * @returns VBox status code.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @param pSession The support driver session.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @param ppVM Where to store the pointer to the VM structure.
42576743851c3c956ad7e867e74df1084c30d434vboxsync * @thread EMT.
42576743851c3c956ad7e867e74df1084c30d434vboxsyncGVMMR0DECL(int) GVMMR0CreateVM(PSUPDRVSESSION pSession, PVM *ppVM)
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync LogFlow(("GVMMR0CreateVM: pSession=%p\n", pSession));
1379dfd407ada5fab15655776896f13b61a951fdvboxsync GVMM_GET_VALID_INSTANCE(pGVMM, VERR_INTERNAL_ERROR);
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync AssertReturn(hEMT != NIL_RTNATIVETHREAD, VERR_INTERNAL_ERROR);
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * The whole allocation process is protected by the lock.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Allocate a handle first so we don't waste resources unnecessarily.
b32be08cd134577ca98e517c019c867c416ec0f2vboxsync /* consistency checks, a bit paranoid as always. */
b32be08cd134577ca98e517c019c867c416ec0f2vboxsync pHandle->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_VM, gvmmR0HandleObjDestructor, pGVMM, pHandle);
42576743851c3c956ad7e867e74df1084c30d434vboxsync * Move the handle from the free to used list and perform permission checks.
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsync rc = SUPR0ObjVerifyAccess(pHandle->pvObj, pSession, NULL);
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsync * Allocate the global VM structure (GVM) and initialize it.
82e3a4017d20f44c30ff909e6b825ff78139cbbbvboxsync /* GMMR0InitPerVMData(pGVM); - later */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Allocate the shared VM structure and associated page array.
42576743851c3c956ad7e867e74df1084c30d434vboxsync const size_t cPages = RT_ALIGN(sizeof(VM), PAGE_SIZE) >> PAGE_SHIFT;
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync rc = RTR0MemObjAllocLow(&pGVM->gvmm.s.VMMemObj, cPages << PAGE_SHIFT, false /* fExecutable */);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync PVM pVM = (PVM)RTR0MemObjAddress(pGVM->gvmm.s.VMMemObj); AssertPtr(pVM);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync rc = RTR0MemObjAllocPage(&pGVM->gvmm.s.VMPagesMemObj, cPages * sizeof(SUPPAGE), false /* fExecutable */);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync PSUPPAGE paPages = (PSUPPAGE)RTR0MemObjAddress(pGVM->gvmm.s.VMPagesMemObj); AssertPtr(paPages);
20f21077abf35d7b7b618acb159267933907407fvboxsync paPages[iPage].Phys = RTR0MemObjGetPagePhysAddr(pGVM->gvmm.s.VMMemObj, iPage);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Map them into ring-3.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync rc = RTR0MemObjMapUser(&pGVM->gvmm.s.VMMapObj, pGVM->gvmm.s.VMMemObj, (RTR3PTR)-1, 0,
e250515922582e0410c9bcb6d24b0f17bef083a0vboxsync RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync pVM->pVMR3 = RTR0MemObjAddressR3(pGVM->gvmm.s.VMMapObj);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync rc = RTR0MemObjMapUser(&pGVM->gvmm.s.VMPagesMapObj, pGVM->gvmm.s.VMPagesMemObj, (RTR3PTR)-1, 0,
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync pVM->paVMPagesR3 = RTR0MemObjAddressR3(pGVM->gvmm.s.VMPagesMapObj);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /* complete the handle - take the UsedLock sem just to be careful. */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync Log(("GVMMR0CreateVM: pVM=%p pVMR3=%p pGVM=%p hGVM=%d\n", pVM, pVM->pVMR3, pGVM, iHandle));
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync RTR0MemObjFree(pGVM->gvmm.s.VMMapObj, false /* fFreeMappings */);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync RTR0MemObjFree(pGVM->gvmm.s.VMPagesMemObj, false /* fFreeMappings */);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync RTR0MemObjFree(pGVM->gvmm.s.VMMemObj, false /* fFreeMappings */);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /* else: The user wasn't permitted to create this VM. */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * The handle will be freed by gvmmR0HandleObjDestructor as we release the
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * object reference here. A little extra mess because of non-recursive lock.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync SUPR0Printf("GVMMR0CreateVM: failed, rc=%d\n", rc);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Initializes the per VM data belonging to GVMM.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param pGVM Pointer to the global VM structure.
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync AssertCompile(RT_SIZEOFMEMB(GVM,gvmm.s) <= RT_SIZEOFMEMB(GVM,gvmm.padding));
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync Assert(RT_SIZEOFMEMB(GVM,gvmm.s) <= RT_SIZEOFMEMB(GVM,gvmm.padding));
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Does the VM initialization.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @returns VBox status code.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pVM Pointer to the shared VM structure.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Validate the VM structure, state and handle.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync if (pGVM->gvmm.s.HaltEventMulti == NIL_RTSEMEVENTMULTI)
1379dfd407ada5fab15655776896f13b61a951fdvboxsync rc = RTSemEventMultiCreate(&pGVM->gvmm.s.HaltEventMulti);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Destroys the VM, freeing all associated resources (the ring-0 ones anyway).
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * This is call from the vmR3DestroyFinalBit and from a error path in VMR3Create,
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * and the caller is not the EMT thread, unfortunately. For security reasons, it
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * would've been nice if the caller was actually the EMT thread or that we somehow
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * could've associated the calling thread with the VM up front.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @returns VBox status code.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param pVM Where to store the pointer to the VM structure.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @thread EMT if it's associated with the VM, otherwise any thread.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync GVMM_GET_VALID_INSTANCE(pGVMM, VERR_INTERNAL_ERROR);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Validate the VM structure, state and caller.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync AssertReturn(!((uintptr_t)pVM & PAGE_OFFSET_MASK), VERR_INVALID_POINTER);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync AssertMsgReturn(pVM->enmVMState >= VMSTATE_CREATING && pVM->enmVMState <= VMSTATE_TERMINATED, ("%d\n", pVM->enmVMState), VERR_WRONG_ORDER);
20f21077abf35d7b7b618acb159267933907407fvboxsync AssertReturn(hGVM != NIL_GVM_HANDLE, VERR_INVALID_HANDLE);
20f21077abf35d7b7b618acb159267933907407fvboxsync AssertReturn(hGVM < RT_ELEMENTS(pGVMM->aHandles), VERR_INVALID_HANDLE);
20f21077abf35d7b7b618acb159267933907407fvboxsync AssertReturn(pHandle->hEMT == hSelf || pHandle->hEMT == NIL_RTNATIVETHREAD, VERR_NOT_OWNER);
20f21077abf35d7b7b618acb159267933907407fvboxsync * Lookup the handle and destroy the object.
20f21077abf35d7b7b618acb159267933907407fvboxsync * Since the lock isn't recursive and we'll have to leave it before dereferencing the
20f21077abf35d7b7b618acb159267933907407fvboxsync * object, we take some precautions against racing callers just in case...
20f21077abf35d7b7b618acb159267933907407fvboxsync /* be careful here because we might theoretically be racing someone else cleaning up. */
20f21077abf35d7b7b618acb159267933907407fvboxsync SUPR0Printf("GVMMR0DestroyVM: pHandle=%p:{.pVM=%p, hEMT=%p, .pvObj=%p} pVM=%p hSelf=%p\n",
1379dfd407ada5fab15655776896f13b61a951fdvboxsync pHandle, pHandle->pVM, pHandle->hEMT, pHandle->pvObj, pVM, hSelf);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Handle destructor.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param pvGVMM The GVM instance pointer.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param pvHandle The handle pointer.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsyncstatic DECLCALLBACK(void) gvmmR0HandleObjDestructor(void *pvObj, void *pvGVMM, void *pvHandle)
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync LogFlow(("gvmmR0HandleObjDestructor: %p %p %p\n", pvObj, pvGVMM, pvHandle));
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * Some quick, paranoid, input validation.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync const uint16_t iHandle = pHandle - &pGVMM->aHandles[0];
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync SUPR0Printf("GVM: handle %d is out of range or corrupt (iSelf=%d)!\n", iHandle, pHandle->iSelf);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * This is a tad slow but a doubly linked list is too much hazzle.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync if (RT_UNLIKELY(pHandle->iNext >= RT_ELEMENTS(pGVMM->aHandles)))
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync SUPR0Printf("GVM: used list index %d is out of range!\n", pHandle->iNext);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync if (RT_UNLIKELY(iPrev >= RT_ELEMENTS(pGVMM->aHandles)))
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync SUPR0Printf("GVM: used list index %d is out of range!\n");
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync if (RT_UNLIKELY(c-- <= 0))
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync SUPR0Printf("GVM: can't find the handle previous previous of %d!\n", pHandle->iSelf);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Do the global cleanup round.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /// @todo GMMR0CleanupVM(pGVM);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Do the GVMM cleanup - must be done last.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /* The VM and VM pages mappings/allocations. */
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync rc = RTR0MemObjFree(pGVM->gvmm.s.VMPagesMapObj, false /* fFreeMappings */); AssertRC(rc);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync rc = RTR0MemObjFree(pGVM->gvmm.s.VMMapObj, false /* fFreeMappings */); AssertRC(rc);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync rc = RTR0MemObjFree(pGVM->gvmm.s.VMPagesMemObj, false /* fFreeMappings */); AssertRC(rc);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync rc = RTR0MemObjFree(pGVM->gvmm.s.VMMemObj, false /* fFreeMappings */); AssertRC(rc);
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync /* the GVM structure itself. */
1379dfd407ada5fab15655776896f13b61a951fdvboxsync /* else: GVMMR0CreateVM cleanup. */
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Free the handle.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Reacquire the UsedLock here to since we're updating handle fields.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync ASMAtomicXchgPtr((void * volatile *)&pHandle->pGVM, NULL);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync ASMAtomicXchgPtr((void * volatile *)&pHandle->pVM, NULL);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync ASMAtomicXchgPtr((void * volatile *)&pHandle->pvObj, NULL);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync ASMAtomicXchgPtr((void * volatile *)&pHandle->pSession, NULL);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync ASMAtomicXchgSize(&pHandle->hEMT, NIL_RTNATIVETHREAD);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Lookup a GVM structure by its handle.
e89bf42607ac3c1b6c60fabbf6067a38adb1284bvboxsync * @returns The GVM pointer on success, NULL on failure.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param hGVM The global VM handle. Asserts on bad handle.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Validate.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync AssertReturn(hGVM < RT_ELEMENTS(pGVMM->aHandles), NULL);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Look it up.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Lookup a GVM structure by the shared VM structure.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @returns VBox status code.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param pVM The shared VM structure (the ring-0 mapping).
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync * @param ppGVM Where to store the GVM pointer.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param ppGVMM Where to store the pointer to the GVMM instance data.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param fTakeUsedLock Whether to take the used lock or not.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Be very careful if not taking the lock as it's possible that
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * the VM will disappear then.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @remark This will not assert on an invalid pVM but try return sliently.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsyncstatic int gvmmR0ByVM(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM, bool fTakeUsedLock)
2d66abeefb9716ed570bb5714884d3fe08629452vboxsync GVMM_GET_VALID_INSTANCE(pGVMM, VERR_INTERNAL_ERROR);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Validate.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync if (RT_UNLIKELY( pVM->enmVMState < VMSTATE_CREATING
cdcfac625bb49f1d4b67aaf8fb8b1cdb69fe49c2vboxsync * Look it up.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Lookup a GVM structure by the shared VM structure.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @returns The GVM pointer on success, NULL on failure.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param pVM The shared VM structure (the ring-0 mapping).
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @remark This will not take the 'used'-lock because it doesn't do
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * nesting and this function will be used from under the lock.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync int rc = gvmmR0ByVM(pVM, &pGVM, &pGVMM, false /* fTakeUsedLock */);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Lookup a GVM structure by the shared VM structure
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * and ensuring that the caller is the EMT thread.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @returns VBox status code.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param pVM The shared VM structure (the ring-0 mapping).
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param ppGVM Where to store the GVM pointer.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @param ppGVMM Where to store the pointer to the GVMM instance data.
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @thread EMT
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * @remark This will assert in failure paths.
2d66abeefb9716ed570bb5714884d3fe08629452vboxsyncstatic int gvmmR0ByVMAndEMT(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM)
81614fc60e096e714022d10d38b70a36b9b21d48vboxsync GVMM_GET_VALID_INSTANCE(pGVMM, VERR_INTERNAL_ERROR);
1379dfd407ada5fab15655776896f13b61a951fdvboxsync * Validate.
AssertMsgReturn(pHandle->hEMT == hAllegedEMT, ("hEMT %x hAllegedEMT %x\n", pHandle->hEMT, hAllegedEMT), VERR_NOT_OWNER);
return VINF_SUCCESS;
* This is used by the assertion machinery in VMMR0.cpp to avoid causing
return NULL;
return NULL;
unsigned cWoken = 0;
unsigned cHalted = 0;
unsigned cTodo2nd = 0;
unsigned cTodo3rd = 0;
if (u64)
cWoken++;
cHalted++;
cTodo2nd++;
cTodo3rd++;
if (cTodo2nd)
cWoken++;
if (cTodo3rd)
cWoken++;
return cWoken;
return rc;
return rc;
return rc;
if (!fYield)
return rc;
if (pVM)
return rc;
return VINF_SUCCESS;
AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);
if (pVM)
return rc;
return VINF_SUCCESS;
AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER);