VMReq.cpp revision 4bfa7b58e362a1bca0628643c352c137900bf01a
919N/A * Copyright (C) 2006-2007 Oracle Corporation 919N/A * This file is part of VirtualBox Open Source Edition (OSE), as 919N/A * you can redistribute it and/or modify it under the terms of the GNU 919N/A * General Public License (GPL) as published by the Free Software 919N/A * Foundation, in version 2 as it comes in the "COPYING" file of the 919N/A * VirtualBox OSE distribution. VirtualBox OSE is distributed in the 919N/A * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 919N/A/******************************************************************************* 919N/A*******************************************************************************/ 98N/A/******************************************************************************* 493N/A*******************************************************************************/ 705N/A * Allocate and queue a call request. 720N/A * If it's desired to poll on the completion of the request set cMillies 98N/A * to 0 and use VMR3ReqWait() to check for completion. In the other case 606N/A * use RT_INDEFINITE_WAIT. 606N/A * The returned request packet must be freed using VMR3ReqFree(). 493N/A * @returns VBox status code. 493N/A * Will not return VERR_INTERRUPTED. 493N/A * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. 493N/A * @param pVM Pointer to the VM. 98N/A * @param idDstCpu The destination CPU(s). Either a specific CPU ID or 493N/A * one of the following special values: 705N/A * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. 98N/A * @param ppReq Where to store the pointer to the request. 98N/A * This will be NULL or a valid request pointer not matter what happens. 493N/A * @param cMillies Number of milliseconds to wait for the request to 98N/A * be completed. Use RT_INDEFINITE_WAIT to only 493N/A * wait till it's completed. * @param fFlags A combination of the VMREQFLAGS values. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Convenience wrapper for VMR3ReqCallU. * This assumes (1) you're calling a function that returns an VBox status code, * (2) that you want it's return code on success, and (3) that you wish to wait * for ever for it to return. * @returns VBox status code. In the unlikely event that VMR3ReqCallVU fails, * its status code is return. Otherwise, the status of pfnFunction is * @param pVM Pointer to the VM. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Convenience wrapper for VMR3ReqCallU. * This assumes (1) you're calling a function that returns an VBox status code * and that you do not wish to wait for it to complete. * @returns VBox status code returned by VMR3ReqCallVU. * @param pVM Pointer to the VM. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Convenience wrapper for VMR3ReqCallU. * This assumes (1) you're calling a function that returns void, and (2) that * you wish to wait for ever for it to return. * @returns VBox status code of VMR3ReqCallVU. * @param pVM Pointer to the VM. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Convenience wrapper for VMR3ReqCallU. * This assumes (1) you're calling a function that returns void, and (2) that * you do not wish to wait for it to complete. * @returns VBox status code of VMR3ReqCallVU. * @param pVM Pointer to the VM. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Convenience wrapper for VMR3ReqCallU. * This assumes (1) you're calling a function that returns an VBox status code, * (2) that you want it's return code on success, (3) that you wish to wait for * ever for it to return, and (4) that it's priority request that can be safely * be handled during async suspend and power off. * @returns VBox status code. In the unlikely event that VMR3ReqCallVU fails, * its status code is return. Otherwise, the status of pfnFunction is * @param pVM Pointer to the VM. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Convenience wrapper for VMR3ReqCallU. * This assumes (1) you're calling a function that returns void, (2) that you * wish to wait for ever for it to return, and (3) that it's priority request * that can be safely be handled during async suspend and power off. * @returns VBox status code of VMR3ReqCallVU. * @param pVM Pointer to the VM. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Allocate and queue a call request to a void function. * If it's desired to poll on the completion of the request set cMillies * to 0 and use VMR3ReqWait() to check for completion. In the other case * use RT_INDEFINITE_WAIT. * The returned request packet must be freed using VMR3ReqFree(). * @returns VBox status code. * Will not return VERR_INTERRUPTED. * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. * @param pUVM Pointer to the user mode VM structure. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param ppReq Where to store the pointer to the request. * This will be NULL or a valid request pointer not matter what happens, unless fFlags * contains VMREQFLAGS_NO_WAIT when it will be optional and always NULL. * @param cMillies Number of milliseconds to wait for the request to * be completed. Use RT_INDEFINITE_WAIT to only * wait till it's completed. * @param fFlags A combination of the VMREQFLAGS values. * @param pfnFunction Pointer to the function to call. * @param cArgs Number of arguments following in the ellipsis. * @param ... Function arguments. * @remarks See remarks on VMR3ReqCallVU. * Allocate and queue a call request. * If it's desired to poll on the completion of the request set cMillies * to 0 and use VMR3ReqWait() to check for completion. In the other case * use RT_INDEFINITE_WAIT. * The returned request packet must be freed using VMR3ReqFree(). * @returns VBox status code. * Will not return VERR_INTERRUPTED. * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. * @param pUVM Pointer to the user mode VM structure. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * @param ppReq Where to store the pointer to the request. * This will be NULL or a valid request pointer not matter what happens, unless fFlags * contains VMREQFLAGS_NO_WAIT when it will be optional and always NULL. * @param cMillies Number of milliseconds to wait for the request to * be completed. Use RT_INDEFINITE_WAIT to only * wait till it's completed. * @param pfnFunction Pointer to the function to call. * @param fFlags A combination of the VMREQFLAGS values. * @param cArgs Number of arguments following in the ellipsis. * Stuff which differs in size from uintptr_t is gonna make trouble, so don't try! * @param Args Argument vector. * - Do not pass anything which is larger than an uintptr_t. * - 64-bit integers are larger than uintptr_t on 32-bit hosts. * Pass integers > 32-bit by reference (pointers). * - Don't use NULL since it should be the integer 0 in C++ and may * therefore end up with garbage in the bits 63:32 on 64-bit * hosts because 'int' is 32-bit. * Use (void *)NULL or (uintptr_t)0 instead of NULL. * Initialize the request data. * Queue the request and return. LogFlow((
"VMR3ReqCallV: returns %Rrc\n",
rc));
* Joins the list pList with whatever is linked up at *pHead. * Joins the list pList with whatever is linked up at *pHead. * Split the list if it's too long. * Allocates a request packet. * The caller allocates a request packet, fills in the request data * union and queues the request. * @returns VBox status code. * @param ppReq Where to store the pointer to the allocated packet. * @param enmType Package type. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. * Allocates a request packet. * The caller allocates a request packet, fills in the request data * union and queues the request. * @returns VBox status code. * @param pUVM Pointer to the user mode VM structure. * @param ppReq Where to store the pointer to the allocated packet. * @param enmType Package type. * @param idDstCpu The destination CPU(s). Either a specific CPU ID or * one of the following special values: * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. (
"Invalid package type %d valid range %d-%d inclusively.\n",
* Try get a recycled packet. * While this could all be solved with a single list with a lock, it's a sport * of mine to avoid locks. #
if 0
/* sad, but this won't work safely because the reading of pReq->pNext. */ * Make sure the event sem is not signaled. * This shall not happen, but if it does we'll just destroy * the semaphore and create a new one. #
if 0
///@todo @bugref{4725} - def RT_LOCK_STRICT * Initialize the packet and return it. LogFlow((
"VMR3ReqAlloc: returns VINF_SUCCESS *ppReq=%p recycled\n",
pReq));
#
if 0
///@todo @bugref{4725} - def RT_LOCK_STRICT * Initialize the packet and return it. LogFlow((
"VMR3ReqAlloc: returns VINF_SUCCESS *ppReq=%p new\n",
pReq));
* @returns VBox status code. * @param pReq Package to free. * @remark The request packet must be in allocated or completed state! * Ignore NULL (all free functions should do this imho). * Make it a free packet and put it into one of the free packet lists. * The quest must be allocated using VMR3ReqAlloc() and contain * If it's desired to poll on the completion of the request set cMillies * to 0 and use VMR3ReqWait() to check for completion. In the other case * use RT_INDEFINITE_WAIT. * @returns VBox status code. * Will not return VERR_INTERRUPTED. * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. * @param pReq The request to queue. * @param cMillies Number of milliseconds to wait for the request to * be completed. Use RT_INDEFINITE_WAIT to only * wait till it's completed. * Verify the supplied package. (
"Invalid request package! Anyone cooking their own packages???\n"),
(
"Invalid package type %d valid range %d-%d inclusively. This was verified on alloc too...\n",
* Also, store pVM (and fFlags) locally since pReq may be invalid after queuing it. /* Reinit some members. */ /* Reinit some members. */ && ( !
pUVCpu /* and it's not the current thread. */ /* Fetch the right UVMCPU */ LogFlow((
"VMR3ReqQueue: returns %Rrc\n",
rc));
&& !
pUVCpu /* only EMT threads have a valid pointer stored in the TLS slot. */)
/* Note: pUVCpu may or may not be NULL in the VMCPUID_ANY_QUEUE case; we don't care. */ LogFlow((
"VMR3ReqQueue: returns %Rrc\n",
rc));
* The requester was an EMT, just execute it. LogFlow((
"VMR3ReqQueue: returns %Rrc (processed)\n",
rc));
* Wait for a request to be completed. * @returns VBox status code. * @returns VERR_TIMEOUT if cMillies was reached without the packet being completed. * @param pReq The request to wait for. * @param cMillies Number of milliseconds to wait. * Use RT_INDEFINITE_WAIT to only wait till it's completed. * Verify the supplied package. (
"Invalid request package! Anyone cooking their own packages???\n"),
(
"Invalid package type %d valid range %d-%d inclusively. This was verified on alloc too...\n",
* Check for deadlock condition LogFlow((
"VMR3ReqWait: returns %Rrc\n",
rc));
* @param pUVM Pointer to the user mode VM structure. * @param idDstCpu VMCPUID_ANY or the ID of the current CPU. * VMR3ReqProcessU helper that handles cases where there are more than one * @returns The oldest request. * @param pUVM Pointer to the user mode VM structure * @param idDstCpu VMCPUID_ANY or virtual CPU ID. * @param pReqList The list of requests. * @param ppReqs Pointer to the list head. * Chop off the last one (pReq). * Push the others back onto the list (end of it). * Process pending request(s). * This function is called from a forced action handler in the EMT * or from one of the EMT loops. * @returns VBox status code. * @param pUVM Pointer to the user mode VM structure. * @param idDstCpu Pass VMCPUID_ANY to process the common request queue * and the CPU ID for a CPU specific one. In the latter * case the calling thread must be the EMT of that CPU. * @param fPriorityOnly When set, only process the priority request queue. * @note SMP safe (multiple EMTs trying to satisfy VM_FF_REQUESTs). * @remarks This was made reentrant for async PDM handling, the debugger and * Determine which queues to process. * We do not repeat the outer loop if we've got an informational status code * since that code needs processing by our caller (usually EM). * Get the pending requests. * If there are more than one request, unlink the oldest and put the * rest back so that we're reentrant. * @returns VBox status code. * @param pReq Request packet to process. #
if 1 /*def VBOX_STRICT */ * Disable rendezvous if servicing a priority request. Priority requests * can not make use of the EMT rendezvous API. * A packed down call frame. DECLCALLBACKMEMBER(
int,
pfn10)(
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t);
DECLCALLBACKMEMBER(
int,
pfn11)(
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t);
DECLCALLBACKMEMBER(
int,
pfn12)(
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t);
DECLCALLBACKMEMBER(
int,
pfn13)(
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t);
DECLCALLBACKMEMBER(
int,
pfn14)(
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t);
DECLCALLBACKMEMBER(
int,
pfn15)(
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t,
uintptr_t);
case 11:
rcRet = u.
pfn11(
pauArgs[0],
pauArgs[
1],
pauArgs[
2],
pauArgs[
3],
pauArgs[
4],
pauArgs[
5],
pauArgs[
6],
pauArgs[
7],
pauArgs[
8],
pauArgs[
9],
pauArgs[
10]);
break;
case 12:
rcRet = u.
pfn12(
pauArgs[0],
pauArgs[
1],
pauArgs[
2],
pauArgs[
3],
pauArgs[
4],
pauArgs[
5],
pauArgs[
6],
pauArgs[
7],
pauArgs[
8],
pauArgs[
9],
pauArgs[
10],
pauArgs[
11]);
break;
case 13:
rcRet = u.
pfn13(
pauArgs[0],
pauArgs[
1],
pauArgs[
2],
pauArgs[
3],
pauArgs[
4],
pauArgs[
5],
pauArgs[
6],
pauArgs[
7],
pauArgs[
8],
pauArgs[
9],
pauArgs[
10],
pauArgs[
11],
pauArgs[
12]);
break;
case 14:
rcRet = u.
pfn14(
pauArgs[0],
pauArgs[
1],
pauArgs[
2],
pauArgs[
3],
pauArgs[
4],
pauArgs[
5],
pauArgs[
6],
pauArgs[
7],
pauArgs[
8],
pauArgs[
9],
pauArgs[
10],
pauArgs[
11],
pauArgs[
12],
pauArgs[
13]);
break;
case 15:
rcRet = u.
pfn15(
pauArgs[0],
pauArgs[
1],
pauArgs[
2],
pauArgs[
3],
pauArgs[
4],
pauArgs[
5],
pauArgs[
6],
pauArgs[
7],
pauArgs[
8],
pauArgs[
9],
pauArgs[
10],
pauArgs[
11],
pauArgs[
12],
pauArgs[
13],
pauArgs[
14]);
break;
"andl $0xfffffff0, %%esp\n\t" /* Free the packet, nobody is waiting. */ LogFlow((
"vmR3ReqProcessOneU: Completed request %p: rcReq=%Rrc rcRet=%Rrc - freeing it\n",
/* Notify the waiter and him free up the packet. */ LogFlow((
"vmR3ReqProcessOneU: Completed request %p: rcReq=%Rrc rcRet=%Rrc - notifying waiting thread\n",
#
if 1 /*def VBOX_STRICT */ * Restore the rendezvous disabled state.