GVMR0.cpp revision 2f52cd93395fc62c16248772913f1c894dc8040f
/* $Id$ */
/** @file
* GVM - 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_GVM GVM - 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 and assign unique identifiers to
* each of them (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 GVM 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 "GVMInternal.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 ring-0 mapping of the 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 GVM instance data.
*/
typedef struct
{
/** 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. */
} GVM;
/** Pointer to the GVM instance data. */
/** The GVM::u32Magic value (Charlie Haden). */
#define GVM_MAGIC 0x19370806
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Pointer to the GVM instance data.
* (Just my general dislike for global variables.) */
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Initializes the GVM.
*
* This is called while owninng the loader sempahore (see supdrvIOCtl_LdrLoad()).
*
* @returns VBox status code.
*/
{
SUPR0Printf("GVMR0Init:\n");
/*
* Allocate and initialize the instance data.
*/
if (!pGVM)
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.
*/
{
SUPR0Printf("GVMR0Term:\n");
{
return;
}
{
}
}
/**
* 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->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_VM, gvmR0HandleObjDestructor, pGVM, 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 gvmR0HandleObjDestructor 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;
}
/**
* 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, gvmR0HandleObjDestructor, pGVM, 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 gvmR0HandleObjDestructor 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 GVMR0RegisterVM API.
*
*
* @returns VBox status code.
* @param pVM The VM handle.
* @thread EMT.
*/
{
return GVMR0DestroyVM(pVM);
}
#endif /* ... */
/**
* Handle destructor.
*
* @param pvGVM 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("gvmR0HandleObjDestructor: returns\n");
}
/**
* 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;
}