VMMDevHGCM.cpp revision b101b0b2d070b760b4f7496da658e08637348d3d
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * VMMDev - HGCM - Host-Guest Communication Manager Device.
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * available from http://www.virtualbox.org. This file is free software;
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * you can redistribute it and/or modify it under the terms of the GNU
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * General Public License (GPL) as published by the Free Software
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * additional information or have any questions.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync/* Information about a linear ptr parameter. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Index of the parameter. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Offset in the first physical page of the region. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* How many pages. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Pointer to array of the GC physical addresses for these pages.
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync * It is assumed that the physical address of the locked resident
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * guest page does not change.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Active commands, list is protected by critsectHGCMCmdList. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Size of memory buffer for this command structure, including trailing paHostParms.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * This field simplifies loading of saved state.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* The type of the command. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Whether the command was cancelled by the guest. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* GC physical address of the guest request. */
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync /* Request packet size */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Pointer to converted host parameters in case of a Call request.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * Parameters follow this structure in the same memory block.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Linear pointer parameters information. */
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* How many pages for all linptrs of this command.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync * Only valid if cLinPtrs > 0. This field simplifies loading of saved state.
c34f9b1d1526bb5e7fa22d868de402fc50c318fevboxsync /* Pointer to descriptions of linear pointers. */
return rc;
static int vmmdevHGCMAddCommand (VMMDevState *pVMMDevState, PVBOXHGCMCMD pCmd, RTGCPHYS GCPhys, uint32_t cbSize, VBOXHGCMCMDTYPE enmCmdType)
return rc;
return rc;
while (pCmd)
return pCmd;
return rc;
void *pvHost,
Log(("vmmdevHGCMWriteLinPtr: page %d: dst %RGp, src %p, cbWrite %d\n", iPage, GCPhysDst, pu8Src, cbWrite));
iPage++;
u32Size = 0;
return rc;
static void logRelSavedCmdSizeMismatch (const char *pszFunction, uint32_t cbExpected, uint32_t cbCmdSize)
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, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
return VERR_INVALID_PARAMETER;
rc = pVMMDevState->pHGCMDrv->pfnConnect (pVMMDevState->pHGCMDrv, pSavedCmd, &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, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
return VERR_INVALID_PARAMETER;
rc = pVMMDevState->pHGCMDrv->pfnDisconnect (pVMMDevState->pHGCMDrv, pSavedCmd, pHGCMDisconnect->u32ClientID);
*pfHGCMCalled = true;
return rc;
int vmmdevHGCMCall (VMMDevState *pVMMDevState, VMMDevHGCMCall *pHGCMCall, 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:
#ifdef LOG_ENABLED
AssertFailed();
/* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
if (size == 0)
rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
iLinPtr++;
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
#ifdef LOG_ENABLED
AssertFailed();
/* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
if (size == 0)
rc = vmmdevHGCMSaveLinPtr (pVMMDevState->pDevIns, i, linearAddr, size, iLinPtr, pCmd->paLinPtrs, &pPages);
iLinPtr++;
vmmdevHGCMAddCommand (pVMMDevState, pCmd, GCPhys, pHGCMCall->header.header.size, VBOXHGCMCMDTYPE_CALL);
rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pCmd->paHostParms);
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, bool f64Bits, bool *pfHGCMCalled, VBOXHGCMCMD *pSavedCmd)
Log(("vmmdevHGCMCallSaved: client id = %d, function = %d, %s bit\n", pHGCMCall->u32ClientID, pHGCMCall->u32Function, f64Bits? "64": "32"));
if (cParms != 0)
VBOXHGCMSVCPARM *pHostParm = (VBOXHGCMSVCPARM *)((uint8_t *)pSavedCmd + sizeof (struct VBOXHGCMCMD));
int iLinPtr = 0;
if (f64Bits)
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
#ifdef LOG_ENABLED
AssertFailed();
/* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
if (size == 0)
logRelLoadStatePointerIndexMismatch (iParm, pSavedCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pSavedCmd->cLinPtrs);
if (cbRemaining == 0)
iLinPtr++;
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevHGCMParmType_32bit:
case VMMDevHGCMParmType_64bit:
#ifdef LOG_ENABLED
AssertFailed();
/* rc = PDMDevHlpPhys2HCVirt (pVMMDevState->pDevIns, physAddr, size, &pHostParm->u.pointer.addr); */
if (size == 0)
logRelLoadStatePointerIndexMismatch (iParm, pSavedCmd->paLinPtrs[iLinPtr].iParm, iLinPtr, pSavedCmd->cLinPtrs);
if (cbRemaining == 0)
iLinPtr++;
rc = pVMMDevState->pHGCMDrv->pfnCall (pVMMDevState->pHGCMDrv, pSavedCmd, pHGCMCall->u32ClientID, pHGCMCall->u32Function, cParms, pSavedCmd->paHostParms);
*pfHGCMCalled = true;
return rc;
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, HGCMPort)) )
DECLCALLBACK(void) hgcmCompletedWorker (PPDMIHGCMPORT pInterface, int32_t result, PVBOXHGCMCMD pCmd)
#ifdef VBOX_WITH_64_BITS_GUESTS
#ifdef VBOX_WITH_64_BITS_GUESTS
case VMMDevReq_HGCMCall64:
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++;
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++;
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++;
case VMMDevReq_HGCMConnect:
int rc = VMR3ReqCallEx(PDMDevHlpGetVM(pVMMDevState->pDevIns), VMCPUID_ANY, NULL, 0, VMREQFLAGS_NO_WAIT | VMREQFLAGS_VOID,
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;
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, &fHGCMCalled, pIter);
requestHeader->header.rc = vmmdevHGCMDisconnectSaved (pVMMDevState, pHGCMDisconnect, &fHGCMCalled, pIter);
case VBOXHGCMCMDTYPE_CALL:
#ifdef VBOX_WITH_64_BITS_GUESTS
bool f64Bits = false;
requestHeader->header.rc = vmmdevHGCMCallSaved (pVMMDevState, pHGCMCall, f64Bits, &fHGCMCalled, pIter);
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;
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)
return rc;