VMMR0.cpp revision e93b0f43df1b169b3b3584de19b5af04276303a1
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * VMM - Host Context Ring 0.
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * Copyright (C) 2006-2010 Oracle Corporation
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * available from http://www.virtualbox.org. This file is free software;
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * you can redistribute it and/or modify it under the terms of the GNU
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * General Public License (GPL) as published by the Free Software
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/*******************************************************************************
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync* Header Files *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync*******************************************************************************/
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#if defined(_MSC_VER) && defined(RT_ARCH_AMD64) /** @todo check this with with VC7! */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/*******************************************************************************
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync* Internal Functions *
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync*******************************************************************************/
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/*******************************************************************************
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync* Global Variables *
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync*******************************************************************************/
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync/** Drag in necessary library bits.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * The runtime lives here (in VMMR0.r0) and VBoxDD*R0.r0 links against us. */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Initialize the module.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * This is called when we're first loaded.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @returns 0 on success.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @returns VBox status on failure.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Initialize the GVMM, GMM, HWACCM, PGM (Darwin) and INTNET.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync /* bail out */
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * Terminate the module.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * This is called when we're finally unloaded.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * Terminate the internal network service.
2e42e0850e182e37277fe28ba5b5d1c37018e783vboxsync * PGM (Darwin) and HWACCM global cleanup.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Destroy the GMM and GVMM instances.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * Initaties the R0 driver for a particular VM instance.
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * @returns VBox status code.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param pVM The VM instance in question.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @param uSvnRev The SVN revision of the ring-3 part.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * @thread EMT.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Match the SVN revisions.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogRel(("VMMR0InitVM: Revision mismatch, r3=%d r0=%d\n", uSvnRev, VMMGetSvnRev()));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync SUPR0Printf("VMMR0InitVM: Revision mismatch, r3=%d r0=%d\n", uSvnRev, VMMGetSvnRev());
ab93606043a9881487aa83be04191d2f4ea24071vboxsync * Register the EMT R0 logger instance for VCPU 0.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync# if 0 /* testing of the logger. */
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync LogCom(("vmmR0InitVM: before %p\n", RTLogDefaultInstance()));
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync LogCom(("vmmR0InitVM: pfnFlush=%p actual=%p\n", pR0Logger->Logger.pfnFlush, vmmR0LoggerFlush));
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync LogCom(("vmmR0InitVM: pfnLogger=%p actual=%p\n", pR0Logger->Logger.pfnLogger, vmmR0LoggerWrapper));
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync LogCom(("vmmR0InitVM: offScratch=%d fFlags=%#x fDestFlags=%#x\n", pR0Logger->Logger.offScratch, pR0Logger->Logger.fFlags, pR0Logger->Logger.fDestFlags));
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync LogCom(("vmmR0InitVM: after %p reg\n", RTLogDefaultInstance()));
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync RTLogSetDefaultInstanceThread(NULL, pVM->pSession);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync LogCom(("vmmR0InitVM: after %p dereg\n", RTLogDefaultInstance()));
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogCom(("vmmR0InitVM: returned succesfully from direct logger call.\n"));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogCom(("vmmR0InitVM: returned succesfully from direct flush call.\n"));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogCom(("vmmR0InitVM: after %p reg2\n", RTLogDefaultInstance()));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync pR0Logger->Logger.pfnLogger("hello ring-0 logger\n");
89dfdbb56cf9dddad3c7685b41bda1e4e4c1d6f9vboxsync LogCom(("vmmR0InitVM: returned succesfully from direct logger call (2). offScratch=%d\n", pR0Logger->Logger.offScratch));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTLogSetDefaultInstanceThread(NULL, pVM->pSession);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogCom(("vmmR0InitVM: after %p dereg2\n", RTLogDefaultInstance()));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTLogLoggerEx(&pR0Logger->Logger, 0, ~0U, "hello ring-0 logger (RTLogLoggerEx)\n");
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogCom(("vmmR0InitVM: RTLogLoggerEx returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
ab93606043a9881487aa83be04191d2f4ea24071vboxsync RTLogPrintf("hello ring-0 logger (RTLogPrintf)\n");
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync LogCom(("vmmR0InitVM: RTLogPrintf returned fine offScratch=%d\n", pR0Logger->Logger.offScratch));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync Log(("Switching to per-thread logging instance %p (key=%p)\n", &pR0Logger->Logger, pVM->pSession));
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTLogSetDefaultInstanceThread(&pR0Logger->Logger, (uintptr_t)pVM->pSession);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync#endif /* LOG_ENABLED */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Initialize the per VM data for GVMM and GMM.
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync// if (RT_SUCCESS(rc))
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync// rc = GMMR0InitPerVMData(pVM);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Init HWACCM, CPUM and PGM (Darwin only).
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync rc = CPUMR0Init(pVM); /** @todo rename to CPUMR0InitVM */
8fdb63a0d23d1618724f651b8c3d11be48b44d35vboxsync /* bail out */
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync RTLogSetDefaultInstanceThread(NULL, (uintptr_t)pVM->pSession);
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * Terminates the R0 driver for a particular VM instance.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * This is normally called by ring-3 as part of the VM termination process, but
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * may alternatively be called during the support driver session cleanup when
d605d5391db09e6395a1c091f148f4b86af84bd3vboxsync * the VM object is destroyed (see GVMM).
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * @returns VBox status code.
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * @param pVM The VM instance in question.
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * @param pGVM Pointer to the global VM structure. Optional.
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * @thread EMT or session clean up thread.
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * Tell GVMM what we're up to and check that we only do this once.
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync * Deregister the logger.
68308f6fe3c9a03c39acd9615d767ad0b3b5dcedvboxsync RTLogSetDefaultInstanceThread(NULL, (uintptr_t)pVM->pSession);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Record return code statistics
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * @param pVM The VM handle.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * @param pVCpu The VMCPU handle.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync * @param rc The status code.
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsyncstatic void vmmR0RecordRC(PVM pVM, PVMCPU pVCpu, int rc)
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync * Collect statistics.
7e10aea6606a51d35041e5a85f9e4f1bd19c4062vboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetInterruptHyper);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetRingSwitchInt);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetStaleSelector);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIOReadWrite);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIOPatchRead);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetMMIOPatchWrite);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetIOBlockEmulate);
9e5c26690d45216629b5f588aced8fcfb68c23b6vboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPatchEmulate);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetPatchIretIRQ);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetRescheduleREM);
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetTimerPending);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZRetInterruptPending);
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMPoolGrow);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMMapChunk);
8e342a5c34610667d2b554cb86f1dc2f38a5313cvboxsync STAM_COUNTER_INC(&pVM->vmm.s.StatRZCallPGMAllocHandy);
333e7ab9cd83b32080826d06ac7b1951c684ccb5vboxsync case VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS:
case VINF_PGM_CHANGE_MODE:
case VINF_EM_PENDING_REQUEST:
return VERR_NOT_SUPPORTED;
* The return code is stored in pVM->vmm.s.iLastGZRc.
switch (enmOperation)
case VMMR0_DO_RAW_RUN:
int rc;
bool fVTxDisabled;
#ifdef VBOX_WITH_STATISTICS
case VMMR0_DO_HWACC_RUN:
int rc;
#ifdef LOG_ENABLED
if ( pR0Logger
if (!HWACCMR0SuspendPending())
rc = vmmR0CallRing3SetJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, HWACCMR0RunGuestCode, pVM, pVCpu); /* this may resume code. */
#ifdef VBOX_WITH_STATISTICS
case VMMR0_DO_NOP:
DECLINLINE(bool) vmmR0IsValidSession(PVM pVM, PSUPDRVSESSION pClaimedSession, PSUPDRVSESSION pSession)
if (!pSession)
if (pVM)
static int vmmR0EntryExWorker(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReqHdr, uint64_t u64Arg, PSUPDRVSESSION pSession)
if (pVM)
return VERR_INVALID_POINTER;
return VERR_INVALID_POINTER;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
switch (enmOperation)
case VMMR0_DO_GVMM_CREATE_VM:
return VERR_INVALID_PARAMETER;
case VMMR0_DO_GVMM_DESTROY_VM:
return VERR_INVALID_PARAMETER;
if (!pVM)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_GVMM_SCHED_HALT:
if (pReqHdr)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
case VMMR0_DO_GVMM_SCHED_POKE:
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_GVMM_SCHED_POLL:
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_VMMR0_INIT:
case VMMR0_DO_VMMR0_TERM:
case VMMR0_DO_HWACC_ENABLE:
case VMMR0_DO_HWACC_SETUP_VM:
return rc;
case VMMR0_DO_CALL_HYPERVISOR:
int rc;
bool fVTxDisabled;
return VERR_NOT_SUPPORTED;
return VERR_PGM_NO_CR3_SHADOW_ROOT;
return rc;
return rc;
return VERR_INVALID_CPU_ID;
return VERR_INVALID_CPU_ID;
if (u64Arg)
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_GMM_FREE_PAGES:
if (u64Arg)
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_CPU_ID;
if (u64Arg)
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
if (u64Arg)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_GMM_SEED_CHUNK:
if (pReqHdr)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_CPU_ID;
if (u64Arg)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_CPU_ID;
if (u64Arg)
return VERR_INVALID_PARAMETER;
return VERR_INVALID_CPU_ID;
if ( u64Arg
|| pReqHdr)
return VERR_INVALID_PARAMETER;
#ifdef VBOX_WITH_PAGE_SHARING
return VERR_INVALID_CPU_ID;
if ( u64Arg
|| pReqHdr)
return VERR_INVALID_PARAMETER;
/* Make sure that log flushes can jump back to ring-3; annoying to get an incomplete log (this is risky though as the code doesn't take this into account).
rc = vmmR0CallRing3SetJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, GMMR0CheckSharedModules, pVM, pVCpu); /* this may resume code. */
return rc;
if (u64Arg)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_GCFGM_SET_VALUE:
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
int rc;
return rc;
return VERR_INVALID_PARAMETER;
return VERR_INVALID_PARAMETER;
case VMMR0_DO_INTNET_OPEN:
return VERR_INVALID_PARAMETER;
case VMMR0_DO_INTNET_IF_CLOSE:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFCLOSEREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFGETBUFFERPTRSREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETPROMISCUOUSMODEREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETMACADDRESSREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSETACTIVEREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_INTNET_IF_SEND:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFSENDREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_INTNET_IF_WAIT:
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFWAITREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
if (u64Arg || !pReqHdr || !vmmR0IsValidSession(pVM, ((PINTNETIFWAITREQ)pReqHdr)->pSession, pSession) || idCpu != NIL_VMCPUID)
return VERR_INVALID_PARAMETER;
case VMMR0_DO_NOP:
case VMMR0_DO_SLOW_NOP:
return VINF_SUCCESS;
case VMMR0_DO_TESTS:
return VINF_SUCCESS;
#if HC_ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS) && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
return VERR_INVALID_CPU_ID;
return VERR_NOT_SUPPORTED;
typedef struct VMMR0ENTRYEXARGS
VMMR0DECL(int) VMMR0EntryEx(PVM pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION pSession)
switch (enmOperation)
case VMMR0_DO_GMM_FREE_PAGES:
case VMMR0_DO_VMMR0_INIT:
case VMMR0_DO_VMMR0_TERM:
#ifdef LOG_ENABLED
# ifdef DEBUG
# ifdef DEBUG
if (pVCpu)
# ifdef RT_ARCH_X86
# ifdef DEBUG
# ifdef DEBUG
#ifdef LOG_ENABLED
#ifdef LOG_ENABLED
if (pVM)
if (pVCpu)
#ifdef RT_ARCH_X86
#ifdef RT_OS_LINUX
DECLEXPORT(void) RTCALL RTAssertMsg1Weak(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
if (pVM)
return cbChars;
if (pLog)
if (pVM)
RTStrPrintfV(pVM->vmm.s.szRing0AssertMsg2, sizeof(pVM->vmm.s.szRing0AssertMsg2), pszFormat, vaCopy);