VMMDevHGCM.cpp revision c59743d115dbbe234558cedf5754bec9dce13e62
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * VMMDev - HGCM - Host-Guest Communication Manager Device.
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * Copyright (C) 2006-2007 Oracle Corporation
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * available from http://www.virtualbox.org. This file is free software;
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * General Public License (GPL) as published by the Free Software
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5eabf773597082761832bc0a32b3660e8771f9f1vboxsync# define VBOXDD_HGCMCALL_ENTER(a,b,c,d) do { } while (0)
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync# define VBOXDD_HGCMCALL_COMPLETED_REQ(a,b) do { } while (0)
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync# define VBOXDD_HGCMCALL_COMPLETED_EMT(a,b) do { } while (0)
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync# define VBOXDD_HGCMCALL_COMPLETED_DONE(a,b,c,d) do { } while (0)
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync/* Information about a linear ptr parameter. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Index of the parameter. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Offset in the first physical page of the region. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* How many pages. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Pointer to array of the GC physical addresses for these pages.
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * It is assumed that the physical address of the locked resident
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * guest page does not change.
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Active commands, list is protected by critsectHGCMCmdList. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* The type of the command. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Whether the command was cancelled by the guest. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* GC physical address of the guest request. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Request packet size */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Pointer to converted host parameters in case of a Call request.
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * Parameters follow this structure in the same memory block.
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Linear pointer parameters information. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* How many pages for all linptrs of this command.
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync * Only valid if cLinPtrs > 0. This field simplifies loading of saved state.
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* Pointer to descriptions of linear pointers. */
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsyncstatic int vmmdevHGCMCmdListLock (VMMDevState *pVMMDevState)
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync int rc = RTCritSectEnter (&pVMMDevState->critsectHGCMCmdList);
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsyncstatic void vmmdevHGCMCmdListUnlock (VMMDevState *pVMMDevState)
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync int rc = RTCritSectLeave (&pVMMDevState->critsectHGCMCmdList);
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsyncstatic int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
a7f6f10ecc8705d499ececde41bebf50b7e0568bvboxsync /* PPDMDEVINS pDevIns = pVMMDevState->pDevIns; */
return rc;
return rc;
pCmd;
return pCmd;
return NULL;
return rc;
void *pvHost,
Log(("vmmdevHGCMWriteLinPtr: page %d: dst %RGp, src %p, cbWrite %d\n", iPage, GCPhysDst, pu8Src, cbWrite));
iPage++;
u32Size = 0;
return rc;
iPage++;
static int vmmdevHGCMPageListRead(PPDMDEVINSR3 pDevIns, void *pvDst, uint32_t cbDst, const HGCMPageListInfo *pPageListInfo)
return PDMDevHlpPhysRead(pDevIns, pPageListInfo->aPages[0] | pPageListInfo->offFirstPage, pvDst, cbDst);
if (cbRemaining == 0)
return rc;
static int vmmdevHGCMPageListWrite(PPDMDEVINSR3 pDevIns, const HGCMPageListInfo *pPageListInfo, const void *pvSrc, uint32_t cbSrc)
if (cbRemaining == 0)
return rc;
if (pCmd)
vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
return rc;
static int vmmdevHGCMConnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMConnect *pHGCMConnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
if (pCmd)
vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMConnect->header.header.size, VBOXHGCMCMDTYPE_CONNECT);
rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pCmd, &pHGCMConnectCopy->loc, &pHGCMConnectCopy->u32ClientID);
*pfHGCMCalled = true;
return rc;
int vmmdevHGCMDisconnect (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys)
if (pCmd)
vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
return rc;
static int vmmdevHGCMDisconnectSaved (VMMDevState *pVMMDevState, VMMDevHGCMDisconnect *pHGCMDisconnect, RTGCPHYS GCPhys, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
if (pCmd)
vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMDisconnect->header.header.size, VBOXHGCMCMDTYPE_DISCONNECT);
rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pCmd, pHGCMDisconnect->u32ClientID);
*pfHGCMCalled = true;
return rc;
int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, uint32_t cbHGCMCall, RTGCPHYS GCPhys, bool f64Bits)
Log(("vmmdevHGCMCall: client id = %d, function = %d, %s bit\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function, f64Bits? "64": "32"));
uint32_t i;
if (f64Bits)
#ifdef VBOX_WITH_64_BITS_GUESTS
cLinPtrs++;
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
#ifdef VBOX_WITH_64_BITS_GUESTS
cLinPtrs++;
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
return rc;
return VERR_NO_MEMORY;
if (cLinPtrs > 0)
return VERR_NO_MEMORY;
if (cParms != 0)
if (f64Bits)
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
if (size == 0)
rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
iLinPtr++;
HGCMPageListInfo *pPageListInfo = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + pGuestParm->u.PageList.offset);
uint32_t cbPageListInfo = sizeof (HGCMPageListInfo) + (pPageListInfo->cPages - 1) * sizeof (pPageListInfo->aPages[0]);
if (size == 0)
AssertFailed();
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
if (size == 0)
rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
iLinPtr++;
HGCMPageListInfo *pPageListInfo = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + pGuestParm->u.PageList.offset);
uint32_t cbPageListInfo = sizeof (HGCMPageListInfo) + (pPageListInfo->cPages - 1) * sizeof (pPageListInfo->aPages[0]);
if (size == 0)
AssertFailed();
vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
return rc;
static void logRelLoadStatePointerIndexMismatch (uint32_t iParm, uint32_t iSavedParm, int iLinPtr, int cLinPtrs)
LogRel(("Warning: VMMDev load state: a pointer parameter index mismatch %d (expected %d) (%d/%d)\n",
static int vmmdevHGCMCallSaved (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, RTGCPHYS GCPhys, uint32_t cbHGCMCall, bool f64Bits, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd, VBOXHGCMCMD **ppCmd)
Log(("vmmdevHGCMCallSaved: client id = %d, function = %d, %s bit\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function, f64Bits? "64": "32"));
uint32_t i;
if (f64Bits)
#ifdef VBOX_WITH_64_BITS_GUESTS
cLinPtrs++;
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
#ifdef VBOX_WITH_64_BITS_GUESTS
cLinPtrs++;
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
return rc;
AssertFailed();
return VERR_INVALID_PARAMETER;
return VERR_NO_MEMORY;
vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
if (cParms != 0)
int iLinPtr = 0;
if (f64Bits)
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
if (size == 0)
logRelLoadStatePointerIndexMismatch (iParm, pCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pCmd->cLinPtrs);
if (cbRemaining == 0)
iLinPtr++;
HGCMPageListInfo *pPageListInfo = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + pGuestParm->u.PageList.offset);
uint32_t cbPageListInfo = sizeof (HGCMPageListInfo) + (pPageListInfo->cPages - 1) * sizeof (pPageListInfo->aPages[0]);
if (size == 0)
AssertFailed();
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
if (size == 0)
logRelLoadStatePointerIndexMismatch (iParm, pCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pCmd->cLinPtrs);
if (cbRemaining == 0)
iLinPtr++;
HGCMPageListInfo *pPageListInfo = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + pGuestParm->u.PageList.offset);
uint32_t cbPageListInfo = sizeof (HGCMPageListInfo) + (pPageListInfo->cPages - 1) * sizeof (pPageListInfo->aPages[0]);
if (size == 0)
AssertFailed();
rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
*pfHGCMCalled = true;
return rc;
if ( GCPhys == 0
return VERR_INVALID_PARAMETER;
if (pCmd)
return rc;
case VBOXHGCMCMDTYPE_CONNECT:
case VBOXHGCMCMDTYPE_CALL:
#ifdef VBOX_WITH_64_BITS_GUESTS
AssertFailed ();
LogRel(("VMMDEV: Invalid HGCM command: pCmd->enmCmdType = 0x%08X, pHeader->header.requestType = 0x%08X\n",
return VERR_INVALID_PARAMETER;
#define PDMIHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState *) ((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, IHGCMPort)) )
DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
#ifdef VBOX_WITH_DTRACE
#ifdef VBOX_WITH_64_BITS_GUESTS
/** @todo s/pVMMDevState/pThis/g */
* didn't have to mess around with PDMDevHlpPhysRead/Write. We're
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevReq_HGCMCall64:
uint32_t i;
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
if (size > 0)
iLinPtr++;
HGCMPageListInfo *pPageListInfo = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + pGuestParm->u.PageList.offset);
uint32_t cbPageListInfo = sizeof (HGCMPageListInfo) + (pPageListInfo->cPages - 1) * sizeof (pPageListInfo->aPages[0]);
if (size > 0)
/* Copy pHostParm->u.pointer.addr[pHostParm->u.pointer.size] to pages. */
rc = vmmdevHGCMPageListWrite(pVMMDevState->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
# ifdef VBOX_WITH_DTRACE
case VMMDevReq_HGCMCall32:
uint32_t i;
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
if (size > 0)
rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
iLinPtr++;
HGCMPageListInfo *pPageListInfo = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + pGuestParm->u.PageList.offset);
uint32_t cbPageListInfo = sizeof (HGCMPageListInfo) + (pPageListInfo->cPages - 1) * sizeof (pPageListInfo->aPages[0]);
if (size > 0)
/* Copy pHostParm->u.pointer.addr[pHostParm->u.pointer.size] to pages. */
rc = vmmdevHGCMPageListWrite(pVMMDevState->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
# ifdef VBOX_WITH_DTRACE
case VMMDevReq_HGCMCall:
uint32_t i;
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
if (size > 0)
rc = vmmdevHGCMWriteLinPtr (pVMMDevState->pDevIns, i, pHostParm->u.pointer.addr, size, iLinPtr, pCmd->paLinPtrs);
iLinPtr++;
HGCMPageListInfo *pPageListInfo = (HGCMPageListInfo *)((uint8_t *)pHGCMCall + pGuestParm->u.PageList.offset);
uint32_t cbPageListInfo = sizeof (HGCMPageListInfo) + (pPageListInfo->cPages - 1) * sizeof (pPageListInfo->aPages[0]);
if (size > 0)
/* Copy pHostParm->u.pointer.addr[pHostParm->u.pointer.size] to pages. */
rc = vmmdevHGCMPageListWrite(pVMMDevState->pDevIns, pPageListInfo, pHostParm->u.pointer.addr, size);
# ifdef VBOX_WITH_DTRACE
case VMMDevReq_HGCMConnect:
while (pIter)
cCmds++;
if (cCmds > 0)
while (pIter)
return rc;
while (cCmds--)
while (cCmds--)
RTGCPHYS *pPages = (RTGCPHYS *)((uint8_t *)pCmd->paLinPtrs + sizeof (VBOXHGCMLINPTR) * pCmd->cLinPtrs);
int cPages = 0;
cPages++;
return VERR_SSM_UNEXPECTED_DATA;
return rc;
pVMMDevState->pHGCMCmdList = NULL; /* Reset the list. Saved commands will be processed and deallocated. */
while (pIter)
bool fHGCMCalled = false;
return VERR_NO_MEMORY;
Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->header.version, VMMDEV_REQUEST_HEADER_VERSION));
Log(("VMMDev request issued: %d, command type %d\n", requestHeader->header.requestType, pIter->enmCmdType));
case VBOXHGCMCMDTYPE_CONNECT:
requestHeader->header.rc = vmmdevHGCMConnectSaved (pVMMDevState, pHGCMConnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pVMMDevState, pHGCMDisconnect, pIter->GCPhys, &fHGCMCalled, pIter, &pCmd);
case VBOXHGCMCMDTYPE_CALL:
#ifdef VBOX_WITH_64_BITS_GUESTS
bool f64Bits = false;
requestHeader->header.rc = vmmdevHGCMCallSaved (pVMMDevState, pHGCMCall, pIter->GCPhys, requestHeader->header.size, f64Bits, &fHGCMCalled, pIter, &pCmd);
case VMMDevReq_HGCMConnect:
case VMMDevReq_HGCMDisconnect:
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevReq_HGCMCall64:
case VMMDevReq_HGCMCall32:
case VMMDevReq_HGCMCall:
#ifdef VBOX_WITH_64_BITS_GUESTS
bool f64Bits = false;
requestHeader->header.rc = vmmdevHGCMCall (pVMMDevState, pHGCMCall, requestHeader->header.size, pIter->GCPhys, f64Bits);
LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->header.requestType));
LogRel(("VMMDEV: Ignoring unknown request type %x during LoadState\n", requestHeader->header.requestType));
if (!fHGCMCalled)
if (!fHGCMCalled)
if (pCmd)
return rc;