GVMMR0.cpp revision 0ce68d918e23ea207bdb71a535b074d495affcbe
/* $Id$ */
/** @file
* GVMM - Global VM Manager.
*/
/*
* Copyright (C) 2007 InnoTek Systemberatung GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
*/
/** @page pg_GVMM GVMM - The Global VM Manager
*
* The Global VM Manager lives in ring-0. It's main function at the moment
* is to manage a list of all running VMs, keep a ring-0 only structure (GVM)
* for each of them, and assign them unique identifiers (so GMM can track
* page owners). The idea for the future is to add an idle priority kernel
* thread that can take care of tasks like page sharing.
*
* The GVMM will create a ring-0 object for each VM when it's registered,
* this is both for session cleanup purposes and for having a point where
* it's possible to implement usage polices later (in SUPR0ObjRegister).
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_GVM
/* #include "GVMMInternal.h" */
#include <iprt/semaphore.h>
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Global VM handle.
*/
typedef struct GVMHANDLE
{
/** The index of the next handle in the list (free or used). (0 is nil.) */
/** Our own index / handle value. */
/** Whether to free the VM structure or not. */
bool fFreeVM;
/** The pointer to the ring-0 only (aka global) VM structure. */
/** The ring-0 mapping of the shared VM instance data. */
/** The virtual machine object. */
void *pvObj;
/** The session this VM is associated with. */
/** The ring-0 handle of the EMT thread.
* This is used for assertions and similar cases where we need to find the VM handle. */
} GVMHANDLE;
/** Pointer to a global VM handle. */
typedef GVMHANDLE *PGVMHANDLE;
/**
* The GVMM instance data.
*/
typedef struct GVMM
{
/** Eyecatcher / magic. */
/** The index of the head of the free handle chain. (0 is nil.) */
/** The index of the head of the active handle chain. (0 is nil.) */
/** The lock used to serialize registration and deregistration. */
/** The handle array.
* The size of this array defines the maximum number of currently running VMs.
* The first entry is unused as it represents the NIL handle. */
} GVMM;
/** Pointer to the GVMM instance data. */
/** The GVMM::u32Magic value (Charlie Haden). */
#define GVMM_MAGIC 0x19370806
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Pointer to the GVMM instance data.
* (Just my general dislike for global variables.) */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Initializes the GVMM.
*
* This is called while owninng the loader sempahore (see supdrvIOCtl_LdrLoad()).
*
* @returns VBox status code.
*/
GVMMR0DECL(int) GVMMR0Init(void)
{
SUPR0Printf("GVMMR0Init:\n");
/*
* Allocate and initialize the instance data.
*/
if (!pGVMM)
return VERR_NO_MEMORY;
if (RT_SUCCESS(rc))
{
/* the nil handle */
/* the tail */
/* the rest */
while (i-- > 1)
{
}
return VINF_SUCCESS;
}
return rc;
}
/**
* Terminates the GVM.
*
* This is called while owning the loader semaphore (see supdrvLdrFree()).
* And unless something is wrong, there should be absolutely no VMs
* registered at this point.
*/
GVMMR0DECL(void) GVMMR0Term(void)
{
SUPR0Printf("GVMMR0Term:\n");
{
return;
}
{
}
}
#if 0 /* not currently used */
/**
* Allocates the VM structure and registers it with GVM.
*
* @returns VBox status code.
* @param pSession The support driver session.
* @param ppVM Where to store the pointer to the VM structure.
*
* @thread EMT.
*/
{
/*
* The whole allocation process is protected by the lock.
*/
/*
* Allocate a handle first so we don't waste resources unnecessarily.
*/
if (iHandle)
{
/* consistency checks, a bit paranoid as always. */
/*&& !pHandle->pGVM */
{
pHandle->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_VM, gvmmR0HandleObjDestructor, pGVMM, pHandle);
{
/*
* Move the handle from the free to used list and perform permission checks.
*/
if (RT_SUCCESS(rc))
{
/*
* Allocate and initialize the VM structure.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
}
}
/* else: The user wasn't permitted to create this VM. */
/*
* The handle will be freed by gvmmR0HandleObjDestructor as we release the
* object reference here. A little extra mess because of non-recursive lock.
*/
return rc;
}
rc = VERR_NO_MEMORY;
}
else
}
else
return rc;
}
#endif /* not used yet. */
/**
* Deregistres the VM and destroys the VM structure.
*
* @returns VBox status code.
* @param pVM Where to store the pointer to the VM structure.
*
* @thread EMT.
*/
{
/*
* Validate the VM structure, state and caller.
*/
AssertMsgReturn(pVM->enmVMState >= VMSTATE_CREATING && pVM->enmVMState <= VMSTATE_TERMINATED, ("%d\n", pVM->enmVMState), VERR_WRONG_ORDER);
/*
* Lookup the handle and destroy the object.
* Since the lock isn't recursive, we have to make sure nobody can
* race us as we leave the lock and call SUPR0ObjRelease.
*/
/* be very careful here because we might be racing someone else cleaning up... */
{
}
else
{
}
return rc;
}
#if 1 /* this approach is unsafe wrt to the freeing of pVM. Keeping it as a possible fallback for 1.5.x. */
/**
* Register the specified VM with the GGVM.
*
* Permission polices and resource consumption polices may or may
* not be checked that this poin, be ready to deald nicely with failure.
*
* @returns VBox status code.
*
* @param pVM The VM instance data (aka handle), ring-0 mapping of ccourse.
* The VM::hGVM field may be updated by this call.
* @thread EMT.
*/
{
/*
* Validate the VM structure and state.
*/
/*
* Take the lock and call the worker function.
*/
/*
* Allocate a handle.
*/
if (iHandle)
{
/* consistency checks, a bit paranoid as always. */
{
pHandle->pvObj = SUPR0ObjRegister(pVM->pSession, SUPDRVOBJTYPE_VM, gvmmR0HandleObjDestructor, pGVMM, pHandle);
{
/*
* Move the handle from the free to used list and
* perform permission checks.
*/
if (RT_SUCCESS(rc))
{
}
else
{
/*
* The user wasn't permitted to create this VM.
* Must use gvmmR0HandleObjDestructor via SUPR0ObjRelease to do the
* cleanups. The lock isn't recursive, thus the extra mess.
*/
}
if (RT_FAILURE(rc))
return rc;
}
rc = VERR_NO_MEMORY;
}
else
}
else
return rc;
}
/**
* Deregister a VM previously registered using the GVMMR0RegisterVM API.
*
*
* @returns VBox status code.
* @param pVM The VM handle.
* @thread EMT.
*/
{
return GVMMR0DestroyVM(pVM);
}
#endif /* ... */
/**
* Handle destructor.
*
* @param pvGVMM The GVM instance pointer.
* @param pvHandle The handle pointer.
*/
{
/*
* Some quick, paranoid, input validation.
*/
if ( !iHandle
{
return;
}
/*
* This is a tad slow but a doubly linked list is too much hazzle.
*/
{
return;
}
else
{
while (!iPrev)
{
{
SUPR0Printf("GVM: used list index %d is out of range!\n");
return;
}
if (RT_UNLIKELY(c-- <= 0))
{
iPrev = 0;
break;
}
break;
}
if (!iPrev)
{
return;
}
}
/*
* Do the global cleanup round, currently only GMM.
* Can't trust the VM pointer unless it was allocated in ring-0...
*/
{
/// @todo GMMR0CleanupVM(pVM);
/*
* Free the VM structure.
*/
}
/*
* Free the handle.
*/
SUPR0Printf("gvmmR0HandleObjDestructor: returns\n");
}
/**
* Lookup a GVM pointer by its handle.
*
* @returns The GVM pointer on success, NULL on failure.
* @param hGVM The global VM handle. Asserts on bad handle.
*/
{
/*
* Validate.
*/
/*
* Look it up.
*/
}
/**
* Lookup a VM by its global handle.
*
* @returns The VM handle on success, NULL on failure.
* @param hGVM The global VM handle. Asserts on bad handle.
*/
{
/*
* Validate.
*/
/*
* Look it up.
*/
}
/**
* Looks up the VM belonging to the specified EMT thread.
*
* This is used by the assertion machinery in VMMR0.cpp to avoid causing
* unnecessary kernel panics when the EMT thread hits an assertion. The
* call may or not be an EMT thread.
*
* @returns The VM handle on success, NULL on failure.
* @param hEMT The native thread handle of the EMT.
* NIL_RTNATIVETHREAD means the current thread
*/
{
/*
* Be very careful here as we're called in AssertMsgN context.
*/
return NULL;
if (hEMT == NIL_RTNATIVETHREAD)
hEMT = RTThreadNativeSelf();
/*
* Search the handles, we don't dare take the lock (assert).
*/
return NULL;
}