summaryrefslogtreecommitdiffstats
path: root/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/util/vboxhgcm.c')
-rw-r--r--src/VBox/GuestHost/OpenGL/util/vboxhgcm.c2498
1 files changed, 2498 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c b/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c
new file mode 100644
index 00000000..6ea14f9b
--- /dev/null
+++ b/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c
@@ -0,0 +1,2498 @@
+/* $Id: vboxhgcm.c $ */
+/** @file
+ * VBox HGCM connection
+ */
+
+/*
+ * Copyright (C) 2008-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) 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.
+ */
+
+#ifdef RT_OS_WINDOWS
+# include <iprt/win/windows.h>
+# include <ddraw.h>
+#else
+# include <sys/ioctl.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <string.h>
+# include <unistd.h>
+#endif
+
+#include "cr_error.h"
+#include "cr_net.h"
+#include "cr_bufpool.h"
+#include "cr_mem.h"
+#include "cr_string.h"
+#include "cr_endian.h"
+#include "cr_threads.h"
+#include "net_internals.h"
+#include "cr_process.h"
+
+#include <iprt/initterm.h>
+#include <iprt/thread.h>
+
+#include <VBox/VBoxGuestLib.h>
+#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+#include <VBoxCrHgsmi.h>
+#endif
+
+/** @todo move define somewhere else, and make sure it's less than VBGLR0_MAX_HGCM_KERNEL_PARM*/
+/*If we fail to pass data in one chunk, send it in chunks of this size instead*/
+#define CR_HGCM_SPLIT_BUFFER_SIZE (8*_1M)
+
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifdef DEBUG_misha
+#ifdef CRASSERT
+# undef CRASSERT
+#endif
+#define CRASSERT Assert
+#endif
+/*#define IN_GUEST
+#if defined(IN_GUEST)
+#define VBOX_WITH_CRHGSMIPROFILE
+#endif */
+#ifdef VBOX_WITH_CRHGSMIPROFILE
+#include <iprt/time.h>
+#include <stdio.h>
+
+typedef struct VBOXCRHGSMIPROFILE
+{
+ uint64_t cStartTime;
+ uint64_t cStepsTime;
+ uint64_t cSteps;
+} VBOXCRHGSMIPROFILE, *PVBOXCRHGSMIPROFILE;
+
+#define VBOXCRHGSMIPROFILE_GET_TIME_NANO() RTTimeNanoTS()
+#define VBOXCRHGSMIPROFILE_GET_TIME_MILLI() RTTimeMilliTS()
+
+/* 10 sec */
+#define VBOXCRHGSMIPROFILE_LOG_STEP_TIME (10000000000.)
+
+DECLINLINE(void) vboxCrHgsmiProfileStart(PVBOXCRHGSMIPROFILE pProfile)
+{
+ pProfile->cStepsTime = 0;
+ pProfile->cSteps = 0;
+ pProfile->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
+}
+
+DECLINLINE(void) vboxCrHgsmiProfileStep(PVBOXCRHGSMIPROFILE pProfile, uint64_t cStepTime)
+{
+ pProfile->cStepsTime += cStepTime;
+ ++pProfile->cSteps;
+}
+
+typedef struct VBOXCRHGSMIPROFILE_SCOPE
+{
+ uint64_t cStartTime;
+/* bool bDisable;*/
+} VBOXCRHGSMIPROFILE_SCOPE, *PVBOXCRHGSMIPROFILE_SCOPE;
+
+static VBOXCRHGSMIPROFILE g_VBoxProfile;
+
+static void vboxCrHgsmiLog(char * szString, ...)
+{
+ char szBuffer[4096] = {0};
+ va_list pArgList;
+ va_start(pArgList, szString);
+ _vsnprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szString, pArgList);
+ va_end(pArgList);
+
+#ifdef VBOX_WITH_CRHGSMI
+ VBoxCrHgsmiLog(szBuffer);
+#else
+ OutputDebugString(szBuffer);
+#endif
+}
+
+DECLINLINE(void) vboxCrHgsmiProfileLog(PVBOXCRHGSMIPROFILE pProfile, uint64_t cTime)
+{
+ uint64_t profileTime = cTime - pProfile->cStartTime;
+ double percent = ((double)100.0) * pProfile->cStepsTime / profileTime;
+ double cps = ((double)1000000000.) * pProfile->cSteps / profileTime;
+ vboxCrHgsmiLog("hgcm: cps: %.1f, host %.1f%%\n", cps, percent);
+}
+
+DECLINLINE(void) vboxCrHgsmiProfileScopeEnter(PVBOXCRHGSMIPROFILE_SCOPE pScope)
+{
+/* pScope->bDisable = false; */
+ pScope->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
+}
+
+DECLINLINE(void) vboxCrHgsmiProfileScopeExit(PVBOXCRHGSMIPROFILE_SCOPE pScope)
+{
+/* if (!pScope->bDisable) */
+ {
+ uint64_t cTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
+ vboxCrHgsmiProfileStep(&g_VBoxProfile, cTime - pScope->cStartTime);
+ if (VBOXCRHGSMIPROFILE_LOG_STEP_TIME < cTime - g_VBoxProfile.cStartTime)
+ {
+ vboxCrHgsmiProfileLog(&g_VBoxProfile, cTime);
+ vboxCrHgsmiProfileStart(&g_VBoxProfile);
+ }
+ }
+}
+
+
+#define VBOXCRHGSMIPROFILE_INIT() vboxCrHgsmiProfileStart(&g_VBoxProfile)
+#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
+
+#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() \
+ VBOXCRHGSMIPROFILE_SCOPE __vboxCrHgsmiProfileScope; \
+ vboxCrHgsmiProfileScopeEnter(&__vboxCrHgsmiProfileScope);
+
+#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() \
+ vboxCrHgsmiProfileScopeExit(&__vboxCrHgsmiProfileScope); \
+
+
+#else
+#define VBOXCRHGSMIPROFILE_INIT() do {} while (0)
+#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
+#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() do {} while (0)
+#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() do {} while (0)
+#endif
+
+typedef struct {
+ int initialized;
+ int num_conns;
+ CRConnection **conns;
+ CRBufferPool *bufpool;
+#ifdef CHROMIUM_THREADSAFE
+ CRmutex mutex;
+ CRmutex recvmutex;
+#endif
+ CRNetReceiveFuncList *recv_list;
+ CRNetCloseFuncList *close_list;
+#ifdef RT_OS_WINDOWS
+ LPDIRECTDRAW pDirectDraw;
+#endif
+#ifdef IN_GUEST
+ uint32_t u32HostCaps;
+ bool fHostCapsInitialized;
+#endif
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ bool bHgsmiOn;
+#endif
+} CRVBOXHGCMDATA;
+
+static CRVBOXHGCMDATA g_crvboxhgcm = {0,};
+
+typedef enum {
+ CR_VBOXHGCM_USERALLOCATED,
+ CR_VBOXHGCM_MEMORY,
+ CR_VBOXHGCM_MEMORY_BIG
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ ,CR_VBOXHGCM_UHGSMI_BUFFER
+#endif
+} CRVBOXHGCMBUFFERKIND;
+
+#define CR_VBOXHGCM_BUFFER_MAGIC 0xABCDE321
+
+typedef struct CRVBOXHGCMBUFFER {
+ uint32_t magic;
+ CRVBOXHGCMBUFFERKIND kind;
+ union
+ {
+ struct
+ {
+ uint32_t len;
+ uint32_t allocated;
+ };
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ PVBOXUHGSMI_BUFFER pBuffer;
+#endif
+ };
+} CRVBOXHGCMBUFFER;
+
+#ifndef RT_OS_WINDOWS
+ #define TRUE true
+ #define FALSE false
+ #define INVALID_HANDLE_VALUE (-1)
+#endif
+
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+
+/* add sizeof header + page align */
+#define CRVBOXHGSMI_PAGE_ALIGN(_s) (((_s) + 0xfff) & ~0xfff)
+#define CRVBOXHGSMI_BUF_HDR_SIZE() (sizeof (CRVBOXHGCMBUFFER))
+#define CRVBOXHGSMI_BUF_SIZE(_s) CRVBOXHGSMI_PAGE_ALIGN((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
+#define CRVBOXHGSMI_BUF_LOCK_SIZE(_s) ((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
+#define CRVBOXHGSMI_BUF_DATA(_p) ((void*)(((CRVBOXHGCMBUFFER*)(_p)) + 1))
+#define CRVBOXHGSMI_BUF_HDR(_p) (((CRVBOXHGCMBUFFER*)(_p)) - 1)
+#define CRVBOXHGSMI_BUF_OFFSET(_st2, _st1) ((uint32_t)(((uint8_t*)(_st2)) - ((uint8_t*)(_st1))))
+
+static int _crVBoxHGSMIClientInit(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI pHgsmi)
+{
+ int rc;
+ VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
+ pClient->pHgsmi = pHgsmi;
+ Flags.s.fCommand = 1;
+ rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1), Flags, &pClient->pCmdBuffer);
+ if (RT_SUCCESS(rc))
+ {
+ Flags.Value = 0;
+ rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1), Flags, &pClient->pHGBuffer);
+ if (RT_SUCCESS(rc))
+ {
+ pClient->pvHGBuffer = NULL;
+ pClient->bufpool = crBufferPoolInit(16);
+ return VINF_SUCCESS;
+ }
+ else
+ crWarning("_crVBoxHGSMIClientInit: pfnBufferCreate failed to allocate host->guest buffer");
+
+ pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
+ }
+ else
+ crWarning("_crVBoxHGSMIClientInit: pfnBufferCreate failed to allocate cmd buffer");
+
+ pClient->pHgsmi = NULL;
+ return rc;
+}
+
+void _crVBoxHGSMIBufferFree(void *data)
+{
+ PVBOXUHGSMI_BUFFER pBuffer = (PVBOXUHGSMI_BUFFER)data;
+ pBuffer->pfnDestroy(pBuffer);
+}
+
+static int _crVBoxHGSMIClientTerm(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI *ppHgsmi)
+{
+ if (pClient->bufpool)
+ crBufferPoolCallbackFree(pClient->bufpool, _crVBoxHGSMIBufferFree);
+ pClient->bufpool = NULL;
+
+ if (pClient->pHGBuffer)
+ {
+ pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
+ pClient->pHGBuffer = NULL;
+ }
+
+ if (pClient->pCmdBuffer)
+ {
+ pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
+ pClient->pCmdBuffer = NULL;
+ }
+
+ if (ppHgsmi)
+ {
+ *ppHgsmi = pClient->pHgsmi;
+ }
+ pClient->pHgsmi = NULL;
+
+ return VINF_SUCCESS;
+}
+
+
+#ifdef VBOX_CRHGSMI_WITH_D3DDEV
+
+static DECLCALLBACK(HVBOXCRHGSMI_CLIENT) _crVBoxHGSMIClientCreate(PVBOXUHGSMI pHgsmi)
+{
+ PCRVBOXHGSMI_CLIENT pClient = crAlloc(sizeof (CRVBOXHGSMI_CLIENT));
+
+ if (pClient)
+ {
+ int rc = _crVBoxHGSMIClientInit(pClient, pHgsmi);
+ if (RT_SUCCESS(rc))
+ return (HVBOXCRHGSMI_CLIENT)pClient;
+ else
+ crWarning("_crVBoxHGSMIClientCreate: _crVBoxHGSMIClientInit failed rc %d", rc);
+
+ crFree(pCLient);
+ }
+
+ return NULL;
+}
+
+static DECLCALLBACK(void) _crVBoxHGSMIClientDestroy(HVBOXCRHGSMI_CLIENT hClient)
+{
+ PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)hClient;
+ _crVBoxHGSMIClientTerm(pClient, NULL);
+ crFree(pClient);
+}
+#endif
+
+DECLINLINE(PCRVBOXHGSMI_CLIENT) _crVBoxHGSMIClientGet(CRConnection *conn)
+{
+#ifdef VBOX_CRHGSMI_WITH_D3DDEV
+ PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)VBoxCrHgsmiQueryClient();
+ CRASSERT(pClient);
+ return pClient;
+#else
+ if (conn->HgsmiClient.pHgsmi)
+ return &conn->HgsmiClient;
+ {
+ PVBOXUHGSMI pHgsmi = conn->pExternalHgsmi ? conn->pExternalHgsmi : VBoxCrHgsmiCreate();
+ if (pHgsmi)
+ {
+ int rc = _crVBoxHGSMIClientInit(&conn->HgsmiClient, pHgsmi);
+ if (RT_SUCCESS(rc))
+ {
+ CRASSERT(conn->HgsmiClient.pHgsmi);
+ return &conn->HgsmiClient;
+ }
+ else
+ crWarning("_crVBoxHGSMIClientGet: _crVBoxHGSMIClientInit failed rc %d", rc);
+ if (!conn->pExternalHgsmi)
+ VBoxCrHgsmiDestroy(pHgsmi);
+ }
+ else
+ {
+ crWarning("VBoxCrHgsmiCreate failed");
+ }
+ }
+ return NULL;
+#endif
+}
+
+static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
+{
+ PVBOXUHGSMI_BUFFER buf;
+ int rc;
+
+ buf = (PVBOXUHGSMI_BUFFER ) crBufferPoolPop(pClient->bufpool, cbSize);
+
+ if (!buf)
+ {
+ VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
+ crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
+ (void *) pClient->bufpool,
+ cbSize);
+ rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, cbSize, Flags, &buf);
+ if (RT_FAILURE(rc))
+ crWarning("_crVBoxHGSMIBufAlloc: Failed to Create a buffer of size(%d), rc(%d)\n", cbSize, rc);
+ }
+ return buf;
+}
+
+static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufFromHdr(CRVBOXHGCMBUFFER *pHdr)
+{
+ PVBOXUHGSMI_BUFFER pBuf;
+ int rc;
+ CRASSERT(pHdr->magic == CR_VBOXHGCM_BUFFER_MAGIC);
+ CRASSERT(pHdr->kind == CR_VBOXHGCM_UHGSMI_BUFFER);
+ pBuf = pHdr->pBuffer;
+ rc = pBuf->pfnUnlock(pBuf);
+ if (RT_FAILURE(rc))
+ {
+ crWarning("_crVBoxHGSMIBufFromHdr: pfnUnlock failed rc %d", rc);
+ return NULL;
+ }
+ return pBuf;
+}
+
+static void _crVBoxHGSMIBufFree(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf)
+{
+ crBufferPoolPush(pClient->bufpool, pBuf, pBuf->cbBuffer);
+}
+
+static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLock(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
+{
+ /* in theory it is OK to use one cmd buffer for asynch cmd submission
+ * because bDiscard flag should result in allocating a new memory backend if the
+ * allocation is still in use.
+ * However, NOTE: since one and the same semaphore synch event is used for completion notification,
+ * for the notification mechanism working as expected
+ * 1. host must complete commands in the same order as it receives them
+ * (to avoid situation when guest receives notification for another command completion)
+ * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
+ * 3. guest must wait for command completion in the same order as it submits them
+ * in case we can not satisfy any of the above, we should introduce multiple command buffers */
+ CRVBOXHGSMIHDR * pHdr;
+ VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+ int rc;
+ fFlags.Value = 0;
+ fFlags.s.fDiscard = 1;
+ rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
+ if (RT_SUCCESS(rc))
+ return pHdr;
+ crWarning("_crVBoxHGSMICmdBufferLock: pfnLock failed rc %d", rc);
+
+ crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
+ return NULL;
+}
+
+static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLockRo(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
+{
+ /* in theory it is OK to use one cmd buffer for asynch cmd submission
+ * because bDiscard flag should result in allocating a new memory backend if the
+ * allocation is still in use.
+ * However, NOTE: since one and the same semaphore synch event is used for completion notification,
+ * for the notification mechanism working as expected
+ * 1. host must complete commands in the same order as it receives them
+ * (to avoid situation when guest receives notification for another command completion)
+ * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
+ * 3. guest must wait for command completion in the same order as it submits them
+ * in case we can not satisfy any of the above, we should introduce multiple command buffers */
+ CRVBOXHGSMIHDR * pHdr = NULL;
+ VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+ int rc;
+ fFlags.Value = 0;
+ fFlags.s.fReadOnly = 1;
+ rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
+ if (RT_FAILURE(rc))
+ crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
+ return pHdr;
+}
+
+static void _crVBoxHGSMICmdBufferUnlock(PCRVBOXHGSMI_CLIENT pClient)
+{
+ int rc = pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
+ if (RT_FAILURE(rc))
+ crError("Failed to Unlock the command buffer rc(%d)\n", rc);
+}
+
+static int32_t _crVBoxHGSMICmdBufferGetRc(PCRVBOXHGSMI_CLIENT pClient)
+{
+ CRVBOXHGSMIHDR * pHdr;
+ VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+ int rc;
+
+ fFlags.Value = 0;
+ fFlags.s.fReadOnly = 1;
+ rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, sizeof (*pHdr), fFlags, (void**)&pHdr);
+ if (RT_FAILURE(rc))
+ {
+ crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", sizeof (*pHdr), rc);
+ return rc;
+ }
+
+ rc = pHdr->result;
+ AssertRC(rc);
+ pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
+
+ return rc;
+}
+
+DECLINLINE(PVBOXUHGSMI_BUFFER) _crVBoxHGSMIRecvBufGet(PCRVBOXHGSMI_CLIENT pClient)
+{
+ if (pClient->pvHGBuffer)
+ {
+ int rc = pClient->pHGBuffer->pfnUnlock(pClient->pHGBuffer);
+ if (RT_FAILURE(rc))
+ {
+ return NULL;
+ }
+ pClient->pvHGBuffer = NULL;
+ }
+ return pClient->pHGBuffer;
+}
+
+DECLINLINE(void*) _crVBoxHGSMIRecvBufData(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
+{
+ VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+ int rc;
+ CRASSERT(!pClient->pvHGBuffer);
+ fFlags.Value = 0;
+ rc = pClient->pHGBuffer->pfnLock(pClient->pHGBuffer, 0, cbBuffer, fFlags, &pClient->pvHGBuffer);
+ if (RT_SUCCESS(rc))
+ return pClient->pvHGBuffer;
+ else
+ crWarning("_crVBoxHGSMIRecvBufData: pfnLock failed rc %d", rc);
+
+ return NULL;
+}
+
+DECLINLINE(void) _crVBoxHGSMIFillCmd(VBOXUHGSMI_BUFFER_SUBMIT *pSubm, PCRVBOXHGSMI_CLIENT pClient, uint32_t cbData)
+{
+ pSubm->pBuf = pClient->pCmdBuffer;
+ pSubm->offData = 0;
+ pSubm->cbData = cbData;
+ pSubm->fFlags.Value = 0;
+ pSubm->fFlags.s.fDoNotRetire = 1;
+# if 0
+ pSubm->fFlags.bDoNotSignalCompletion = 1; /* <- we do not need that actually since
+ * in case we want completion,
+ * we will block in _crVBoxHGSMICmdBufferGetRc (when locking the buffer)
+ * which is needed for getting the result */
+# endif
+}
+#endif
+
+/* Some forward declarations */
+static void _crVBoxHGCMReceiveMessage(CRConnection *conn);
+
+#ifndef IN_GUEST
+static bool _crVBoxHGCMReadBytes(CRConnection *conn, void *buf, uint32_t len)
+{
+ CRASSERT(conn && buf);
+
+ if (!conn->pBuffer || (conn->cbBuffer<len))
+ return FALSE;
+
+ crMemcpy(buf, conn->pBuffer, len);
+
+ conn->cbBuffer -= len;
+ conn->pBuffer = conn->cbBuffer>0 ? (uint8_t*)conn->pBuffer+len : NULL;
+
+ return TRUE;
+}
+#endif
+
+#ifndef IN_GUEST
+/** @todo get rid of it*/
+static bool _crVBoxHGCMWriteBytes(CRConnection *conn, const void *buf, uint32_t len)
+{
+ CRASSERT(conn && buf);
+
+ /* make sure there's host buffer and it's clear */
+ CRASSERT(conn->pHostBuffer && !conn->cbHostBuffer);
+
+ if (conn->cbHostBufferAllocated < len)
+ {
+ crDebug("Host buffer too small %d out of requested %d bytes, reallocating", conn->cbHostBufferAllocated, len);
+ crFree(conn->pHostBuffer);
+ conn->pHostBuffer = crAlloc(len);
+ if (!conn->pHostBuffer)
+ {
+ conn->cbHostBufferAllocated = 0;
+ crError("OUT_OF_MEMORY trying to allocate %d bytes", len);
+ return FALSE;
+ }
+ conn->cbHostBufferAllocated = len;
+ }
+
+ crMemcpy(conn->pHostBuffer, buf, len);
+ conn->cbHostBuffer = len;
+
+ return TRUE;
+}
+#endif
+
+/**
+ * Send an HGCM request
+ *
+ * @return VBox status code
+ * @param pvData Data pointer
+ * @param cbData Data size
+ */
+static int crVBoxHGCMCall(CRConnection *conn, PVBGLIOCHGCMCALL pData, unsigned cbData)
+{
+#ifdef IN_GUEST
+ int rc;
+# ifndef VBOX_WITH_CRHGSMI
+ RT_NOREF(conn);
+# else
+ PCRVBOXHGSMI_CLIENT pClient = g_crvboxhgcm.bHgsmiOn ? _crVBoxHGSMIClientGet(conn) : NULL;
+ if (pClient)
+ rc = VBoxCrHgsmiCtlConCall(pClient->pHgsmi, pData, cbData);
+ else
+# endif
+ {
+ rc = VbglR3HGCMCall(pData, cbData);
+ if (RT_SUCCESS(rc))
+ { /* likely */ }
+ else
+ {
+ crWarning("vboxCall failed with VBox status code %Rrc\n", rc);
+# ifndef RT_OS_WINDOWS
+ if (rc == VERR_INTERRUPTED)
+ {
+ /* Not sure why we're doing the sleep stuff here. The original coder didn't
+ bother to mention why he thought it necessary. :-( */
+ RTMSINTERVAL msSleep;
+ int i;
+ for (i = 0, msSleep = 50; i < 6; i++, msSleep = msSleep * 2)
+ {
+ RTThreadSleep(msSleep);
+ rc = VbglR3HGCMCall(pData, cbData);
+ if (rc != VERR_INTERRUPTED)
+ {
+ if (RT_SUCCESS(rc))
+ crWarning("vboxCall retry(%i) succeeded", i + 1);
+ else
+ crWarning("vboxCall retry(%i) failed with VBox status code %Rrc", i + 1, rc);
+ break;
+ }
+ }
+ }
+# endif
+ }
+ }
+ return rc;
+
+#else /* IN_GUEST */
+ RT_NOREF(conn, pData, cbData);
+ crError("crVBoxHGCMCall called on host side!");
+ CRASSERT(FALSE);
+ return VERR_NOT_SUPPORTED;
+#endif /* IN_GUEST */
+}
+
+static void *_crVBoxHGCMAlloc(CRConnection *conn)
+{
+ CRVBOXHGCMBUFFER *buf;
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ buf = (CRVBOXHGCMBUFFER *) crBufferPoolPop(g_crvboxhgcm.bufpool, conn->buffer_size);
+
+ if (!buf)
+ {
+ crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
+ (void *) g_crvboxhgcm.bufpool,
+ (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
+
+ /* We're either on host side, or we failed to allocate DDRAW buffer */
+ if (!buf)
+ {
+ crDebug("Using system malloc\n");
+ buf = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size );
+ CRASSERT(buf);
+ buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
+ buf->kind = CR_VBOXHGCM_MEMORY;
+ buf->allocated = conn->buffer_size;
+ }
+ }
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ return (void *)( buf + 1 );
+
+}
+
+static void *crVBoxHGCMAlloc(CRConnection *conn)
+{
+ void *pvBuff;
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ pvBuff = _crVBoxHGCMAlloc(conn);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return pvBuff;
+}
+
+static void _crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
+{
+ int rc;
+ int32_t callRes;
+
+#ifdef IN_GUEST
+ if (conn->u32InjectClientID)
+ {
+ CRVBOXHGCMINJECT parms;
+
+ VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_INJECT, SHCRGL_CPARMS_INJECT);
+
+ parms.u32ClientID.type = VMMDevHGCMParmType_32bit;
+ parms.u32ClientID.u.value32 = conn->u32InjectClientID;
+
+ parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
+ parms.pBuffer.u.Pointer.size = len;
+ parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
+
+ rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
+ callRes = parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
+ }
+ else
+#endif
+ {
+ CRVBOXHGCMWRITE parms;
+
+ VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE, SHCRGL_CPARMS_WRITE);
+
+ parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
+ parms.pBuffer.u.Pointer.size = len;
+ parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
+
+ rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
+ callRes = parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
+ }
+
+ if (RT_FAILURE(rc) || RT_FAILURE(callRes))
+ {
+ crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
+ }
+}
+
+static void crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ _crVBoxHGCMWriteExact(conn, buf, len);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void crVBoxHGCMReadExact( CRConnection *conn, const void *buf, unsigned int len )
+{
+ CRVBOXHGCMREAD parms;
+ int rc;
+ RT_NOREF(buf, len);
+
+ VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_READ, SHCRGL_CPARMS_READ);
+
+ CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
+ parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
+ parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
+ parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
+
+ parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
+ parms.cbBuffer.u.value32 = 0;
+
+ rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
+
+ if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
+ {
+ crWarning("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.Hdr.rc);
+ return;
+ }
+
+ if (parms.cbBuffer.u.value32)
+ {
+ /*conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr; */
+ conn->pBuffer = conn->pHostBuffer;
+ conn->cbBuffer = parms.cbBuffer.u.value32;
+ }
+
+ if (conn->cbBuffer)
+ _crVBoxHGCMReceiveMessage(conn);
+
+}
+
+/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
+ * This halves the number of HGCM calls we do,
+ * most likely crVBoxHGCMPollHost shouldn't be called at all now.
+ */
+static void
+crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, CRVBOXHGCMBUFFERKIND bufferKind)
+{
+ CRVBOXHGCMWRITEREAD parms;
+ int rc;
+
+ VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE_READ, SHCRGL_CPARMS_WRITE_READ);
+
+ parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
+ parms.pBuffer.u.Pointer.size = len;
+ parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
+
+ CRASSERT(!conn->pBuffer); /*make sure there's no data to process*/
+ parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out;
+ parms.pWriteback.u.Pointer.size = conn->cbHostBufferAllocated;
+ parms.pWriteback.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
+
+ parms.cbWriteback.type = VMMDevHGCMParmType_32bit;
+ parms.cbWriteback.u.value32 = 0;
+
+ rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
+
+#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
+ if (VERR_OUT_OF_RANGE==rc && CR_VBOXHGCM_USERALLOCATED==bufferKind)
+ {
+ /*Buffer is too big, so send it in split chunks*/
+ CRVBOXHGCMWRITEBUFFER wbParms;
+
+ VBGL_HGCM_HDR_INIT(&wbParms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE_BUFFER, SHCRGL_CPARMS_WRITE_BUFFER);
+
+ wbParms.iBufferID.type = VMMDevHGCMParmType_32bit;
+ wbParms.iBufferID.u.value32 = 0;
+
+ wbParms.cbBufferSize.type = VMMDevHGCMParmType_32bit;
+ wbParms.cbBufferSize.u.value32 = len;
+
+ wbParms.ui32Offset.type = VMMDevHGCMParmType_32bit;
+ wbParms.ui32Offset.u.value32 = 0;
+
+ wbParms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
+ wbParms.pBuffer.u.Pointer.size = MIN(CR_HGCM_SPLIT_BUFFER_SIZE, len);
+ wbParms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
+
+ if (len<CR_HGCM_SPLIT_BUFFER_SIZE)
+ {
+ crError("VERR_OUT_OF_RANGE in crVBoxHGCMWriteReadExact for %u bytes write", len);
+ return;
+ }
+
+ while (wbParms.pBuffer.u.Pointer.size)
+ {
+ crDebug("SHCRGL_GUEST_FN_WRITE_BUFFER, offset=%u, size=%u", wbParms.ui32Offset.u.value32, wbParms.pBuffer.u.Pointer.size);
+
+ rc = crVBoxHGCMCall(conn, &wbParms.hdr, sizeof(wbParms));
+ if (RT_FAILURE(rc) || RT_FAILURE(wbParms.hdr.Hdr.rc) /** @todo now rc == wbParms.hdr.Hdr.rc */)
+ {
+ crError("SHCRGL_GUEST_FN_WRITE_BUFFER (%i) failed with %x %x\n", wbParms.pBuffer.u.Pointer.size, rc, wbParms.hdr.Hdr.rc);
+ return;
+ }
+
+ wbParms.ui32Offset.u.value32 += wbParms.pBuffer.u.Pointer.size;
+ wbParms.pBuffer.u.Pointer.u.linearAddr += (uintptr_t) wbParms.pBuffer.u.Pointer.size;
+ wbParms.pBuffer.u.Pointer.size = MIN(CR_HGCM_SPLIT_BUFFER_SIZE, len-wbParms.ui32Offset.u.value32);
+ }
+
+ /*now issue GUEST_FN_WRITE_READ_BUFFERED referencing the buffer we'd made*/
+ {
+ CRVBOXHGCMWRITEREADBUFFERED wrbParms;
+
+ VBGL_HGCM_HDR_INIT(&wrbParms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_WRITE_READ_BUFFERED, SHCRGL_CPARMS_WRITE_READ_BUFFERED);
+
+ crMemcpy(&wrbParms.iBufferID, &wbParms.iBufferID, sizeof(HGCMFunctionParameter));
+ crMemcpy(&wrbParms.pWriteback, &parms.pWriteback, sizeof(HGCMFunctionParameter));
+ crMemcpy(&wrbParms.cbWriteback, &parms.cbWriteback, sizeof(HGCMFunctionParameter));
+
+ rc = crVBoxHGCMCall(conn, &wrbParms.hdr, sizeof(wrbParms));
+
+ /*bit of hack to reuse code below*/
+ parms.hdr.Hdr.rc = wrbParms.hdr.Hdr.rc;
+ crMemcpy(&parms.cbWriteback, &wrbParms.cbWriteback, sizeof(HGCMFunctionParameter));
+ crMemcpy(&parms.pWriteback, &wrbParms.pWriteback, sizeof(HGCMFunctionParameter));
+ }
+ }
+#endif
+
+ if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
+ {
+
+ if ((VERR_BUFFER_OVERFLOW == parms.hdr.Hdr.rc) /* && RT_SUCCESS(rc) */)
+ {
+ /* reallocate buffer and retry */
+
+ CRASSERT(parms.cbWriteback.u.value32>conn->cbHostBufferAllocated);
+
+ crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, parms.cbWriteback.u.value32);
+
+ crFree(conn->pHostBuffer);
+ conn->cbHostBufferAllocated = parms.cbWriteback.u.value32;
+ conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
+
+ crVBoxHGCMReadExact(conn, buf, len);
+
+ return;
+ }
+ else
+ {
+ crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x %x\n", len, rc, parms.hdr.Hdr.rc);
+ return;
+ }
+ }
+
+ if (parms.cbWriteback.u.value32)
+ {
+ /*conn->pBuffer = (uint8_t*) parms.pWriteback.u.Pointer.u.linearAddr;*/
+ conn->pBuffer = conn->pHostBuffer;
+ conn->cbBuffer = parms.cbWriteback.u.value32;
+ }
+
+ if (conn->cbBuffer)
+ _crVBoxHGCMReceiveMessage(conn);
+}
+
+static void crVBoxHGCMSend(CRConnection *conn, void **bufp,
+ const void *start, unsigned int len)
+{
+ CRVBOXHGCMBUFFER *hgcm_buffer;
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ if (!bufp) /* We're sending a user-allocated buffer. */
+ {
+#ifndef IN_GUEST
+ /** @todo remove temp buffer allocation in unpacker*/
+ /* we're at the host side, so just store data until guest polls us */
+ _crVBoxHGCMWriteBytes(conn, start, len);
+#else
+ CRASSERT(!conn->u32InjectClientID);
+ crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
+ crVBoxHGCMWriteReadExact(conn, start, len, CR_VBOXHGCM_USERALLOCATED);
+#endif
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return;
+ }
+
+ /* The region [start .. start + len + 1] lies within a buffer that
+ * was allocated with crVBoxHGCMAlloc() and can be put into the free
+ * buffer pool when we're done sending it.
+ */
+
+ hgcm_buffer = (CRVBOXHGCMBUFFER *)(*bufp) - 1;
+ CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
+
+ /* Length would be passed as part of HGCM pointer description
+ * No need to prepend it to the buffer
+ */
+#ifdef IN_GUEST
+ if (conn->u32InjectClientID)
+ {
+ _crVBoxHGCMWriteExact(conn, start, len);
+ }
+ else
+#endif
+ crVBoxHGCMWriteReadExact(conn, start, len, hgcm_buffer->kind);
+
+ /* Reclaim this pointer for reuse */
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ /* Since the buffer's now in the 'free' buffer pool, the caller can't
+ * use it any more. Setting bufp to NULL will make sure the caller
+ * doesn't try to re-use the buffer.
+ */
+ *bufp = NULL;
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void crVBoxHGCMPollHost(CRConnection *conn)
+{
+ CRVBOXHGCMREAD parms;
+ int rc;
+
+ CRASSERT(!conn->pBuffer);
+
+ VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_READ, SHCRGL_CPARMS_READ);
+
+ parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
+ parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
+ parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
+
+ parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
+ parms.cbBuffer.u.value32 = 0;
+
+ rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
+
+ if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
+ {
+ crDebug("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.Hdr.rc);
+ return;
+ }
+
+ if (parms.cbBuffer.u.value32)
+ {
+ conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
+ conn->cbBuffer = parms.cbBuffer.u.value32;
+ }
+}
+
+static void crVBoxHGCMSingleRecv(CRConnection *conn, void *buf, unsigned int len)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ crVBoxHGCMReadExact(conn, buf, len);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void _crVBoxHGCMFree(CRConnection *conn, void *buf)
+{
+ CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
+
+ CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
+
+ /** @todo wrong len for redir buffers*/
+ conn->recv_credits += hgcm_buffer->len;
+
+ switch (hgcm_buffer->kind)
+ {
+ case CR_VBOXHGCM_MEMORY:
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ if (g_crvboxhgcm.bufpool) {
+ /** @todo o'rly? */
+ /* pool may have been deallocated just a bit earlier in response
+ * to a SIGPIPE (Broken Pipe) signal.
+ */
+ crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
+ }
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ break;
+
+ case CR_VBOXHGCM_MEMORY_BIG:
+ crFree( hgcm_buffer );
+ break;
+
+ default:
+ crError( "Weird buffer kind trying to free in crVBoxHGCMFree: %d", hgcm_buffer->kind );
+ }
+}
+
+static void crVBoxHGCMFree(CRConnection *conn, void *buf)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ _crVBoxHGCMFree(conn, buf);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void _crVBoxHGCMReceiveMessage(CRConnection *conn)
+{
+ uint32_t len;
+ CRVBOXHGCMBUFFER *hgcm_buffer;
+ CRMessage *msg;
+ CRMessageType cached_type;
+
+ len = conn->cbBuffer;
+ CRASSERT(len > 0);
+ CRASSERT(conn->pBuffer);
+
+#ifndef IN_GUEST
+ /* Expect only CR_MESSAGE_OPCODES from the guest. */
+ AssertPtrReturnVoid(conn->pBuffer);
+
+ if ( conn->cbBuffer >= sizeof(CRMessageHeader)
+ && ((CRMessageHeader*) (conn->pBuffer))->type == CR_MESSAGE_OPCODES)
+ {
+ /* Looks good. */
+ }
+ else
+ {
+ AssertFailed();
+ /** @todo Find out if this is the expected cleanup. */
+ conn->cbBuffer = 0;
+ conn->pBuffer = NULL;
+ return;
+ }
+#endif
+
+#ifndef IN_GUEST
+ if (conn->allow_redir_ptr)
+ {
+#endif
+ CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
+
+ hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
+ hgcm_buffer->len = sizeof(CRMessageRedirPtr);
+
+ msg = (CRMessage *) (hgcm_buffer + 1);
+
+ msg->header.type = CR_MESSAGE_REDIR_PTR;
+ msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
+ msg->header.conn_id = msg->redirptr.pMessage->conn_id;
+
+#if defined(VBOX_WITH_CRHGSMI) && !defined(IN_GUEST)
+ msg->redirptr.CmdData = conn->CmdData;
+ CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&msg->redirptr.CmdData);
+ CRVBOXHGSMI_CMDDATA_CLEANUP(&conn->CmdData);
+#endif
+
+ cached_type = msg->redirptr.pMessage->type;
+
+ conn->cbBuffer = 0;
+ conn->pBuffer = NULL;
+#ifndef IN_GUEST
+ }
+ else
+ {
+ /* we should NEVER have redir_ptr disabled with HGSMI command now */
+ CRASSERT(!conn->CmdData.pvCmd);
+ if ( len <= conn->buffer_size )
+ {
+ /* put in pre-allocated buffer */
+ hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
+ }
+ else
+ {
+ /* allocate new buffer,
+ * not using pool here as it's most likely one time transfer of huge texture
+ */
+ hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
+ hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
+ hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
+ hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
+ }
+
+ hgcm_buffer->len = len;
+ _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
+
+ msg = (CRMessage *) (hgcm_buffer + 1);
+ cached_type = msg->header.type;
+ }
+#endif /* !IN_GUEST*/
+
+ conn->recv_credits -= len;
+ conn->total_bytes_recv += len;
+ conn->recv_count++;
+
+ crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
+
+ /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
+ * OOB messages are the programmer's problem. -- Humper 12/17/01
+ */
+ if (cached_type != CR_MESSAGE_OPCODES
+ && cached_type != CR_MESSAGE_OOB
+ && cached_type != CR_MESSAGE_GATHER)
+ {
+ _crVBoxHGCMFree(conn, msg);
+ }
+}
+
+static void crVBoxHGCMReceiveMessage(CRConnection *conn)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ _crVBoxHGCMReceiveMessage(conn);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+
+/*
+ * Called on host side only, to "accept" client connection
+ */
+static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
+{
+ RT_NOREF(hostname, port);
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+ CRASSERT(conn && conn->pHostBuffer);
+#ifdef IN_GUEST
+ CRASSERT(FALSE);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static int crVBoxHGCMSetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
+{
+ CRVBOXHGCMSETVERSION parms;
+ int rc;
+ RT_NOREF(vMajor, vMinor);
+
+ VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_VERSION, SHCRGL_CPARMS_SET_VERSION);
+
+ parms.vMajor.type = VMMDevHGCMParmType_32bit;
+ parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
+ parms.vMinor.type = VMMDevHGCMParmType_32bit;
+ parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
+
+ rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
+ if (RT_SUCCESS(rc))
+ {
+ conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
+ conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
+
+ return VINF_SUCCESS;
+ }
+ else
+ WARN(("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
+ parms.vMajor.u.value32, parms.vMinor.u.value32));
+ }
+ else
+ WARN(("crVBoxHGCMCall failed %d", rc));
+
+ return rc;
+}
+
+static int crVBoxHGCMGetHostCapsLegacy(CRConnection *conn, uint32_t *pu32HostCaps)
+{
+ CRVBOXHGCMGETCAPS caps;
+ int rc;
+
+ VBGL_HGCM_HDR_INIT(&caps.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_GET_CAPS_LEGACY, SHCRGL_CPARMS_GET_CAPS_LEGACY);
+
+ caps.Caps.type = VMMDevHGCMParmType_32bit;
+ caps.Caps.u.value32 = 0;
+
+ rc = crVBoxHGCMCall(conn, &caps.hdr, sizeof(caps));
+
+ if (RT_SUCCESS(rc))
+ {
+ rc = caps.hdr.Hdr.rc;
+ if (RT_SUCCESS(rc))
+ {
+ *pu32HostCaps = caps.Caps.u.value32;
+ return VINF_SUCCESS;
+ }
+ else
+ WARN(("SHCRGL_GUEST_FN_GET_CAPS failed %d", rc));
+ return FALSE;
+ }
+ else
+ WARN(("crVBoxHGCMCall failed %d", rc));
+
+ *pu32HostCaps = 0;
+
+ return rc;
+}
+
+static int crVBoxHGCMSetPID(CRConnection *conn, unsigned long long pid)
+{
+ CRVBOXHGCMSETPID parms;
+ int rc;
+
+ VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_PID, SHCRGL_CPARMS_SET_PID);
+
+ parms.u64PID.type = VMMDevHGCMParmType_64bit;
+ parms.u64PID.u.value64 = pid;
+
+ rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
+
+ if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
+ {
+ crWarning("SHCRGL_GUEST_FN_SET_PID failed!");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * The function that actually connects. This should only be called by clients,
+ * guests in vbox case.
+ * Servers go through crVBoxHGCMAccept;
+ */
+static int crVBoxHGCMDoConnect( CRConnection *conn )
+{
+#ifdef IN_GUEST
+ int rc;
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+ RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
+ rc = VbglR3InitUser();
+ if (RT_SUCCESS(rc))
+ {
+ uint32_t idClient;
+ rc = VbglR3HGCMConnect("VBoxSharedCrOpenGL", &idClient);
+ if (RT_SUCCESS(rc))
+ {
+ conn->u32ClientID = idClient;
+ crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
+
+ rc = crVBoxHGCMSetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxHGCMSetVersion failed %d", rc));
+ return FALSE;
+ }
+#ifdef RT_OS_WINDOWS
+ rc = crVBoxHGCMSetPID(conn, GetCurrentProcessId());
+#else
+ rc = crVBoxHGCMSetPID(conn, crGetPID());
+#endif
+ if (RT_FAILURE(rc))
+ {
+ WARN(("crVBoxHGCMSetPID failed %Rrc", rc));
+ return FALSE;
+ }
+
+ if (!g_crvboxhgcm.fHostCapsInitialized)
+ {
+ rc = crVBoxHGCMGetHostCapsLegacy(conn, &g_crvboxhgcm.u32HostCaps);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %Rrc", rc));
+ g_crvboxhgcm.u32HostCaps = 0;
+ }
+
+ /* host may not support it, ignore any failures */
+ g_crvboxhgcm.fHostCapsInitialized = true;
+ }
+
+ if (g_crvboxhgcm.u32HostCaps & CR_VBOX_CAP_HOST_CAPS_NOT_SUFFICIENT)
+ {
+ crDebug("HGCM connect: insufficient host capabilities\n");
+ g_crvboxhgcm.u32HostCaps = 0;
+ return FALSE;
+ }
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return TRUE;
+ }
+
+ crDebug("HGCM connect failed: %Rrc\n", rc);
+ VbglR3Term();
+ }
+ else
+ crDebug("Failed to initialize VbglR3 library: %Rrc\n", rc);
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return FALSE;
+
+#else /* !IN_GUEST */
+ crError("crVBoxHGCMDoConnect called on host side!");
+ CRASSERT(FALSE);
+ return FALSE;
+#endif /* !IN_GUEST */
+}
+
+static bool _crVBoxCommonDoDisconnectLocked( CRConnection *conn )
+{
+ int i;
+ if (conn->pHostBuffer)
+ {
+ crFree(conn->pHostBuffer);
+ conn->pHostBuffer = NULL;
+ conn->cbHostBuffer = 0;
+ conn->cbHostBufferAllocated = 0;
+ }
+
+ conn->pBuffer = NULL;
+ conn->cbBuffer = 0;
+
+ if (conn->type == CR_VBOXHGCM)
+ {
+ --g_crvboxhgcm.num_conns;
+
+ if (conn->index < g_crvboxhgcm.num_conns)
+ {
+ g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
+ g_crvboxhgcm.conns[conn->index]->index = conn->index;
+ }
+ else g_crvboxhgcm.conns[conn->index] = NULL;
+
+ conn->type = CR_NO_CONNECTION;
+ }
+
+ for (i = 0; i < g_crvboxhgcm.num_conns; i++)
+ if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
+ return true;
+ return false;
+}
+
+/** @todo same, replace DeviceIoControl with vbglR3DoIOCtl */
+static void crVBoxHGCMDoDisconnect( CRConnection *conn )
+{
+ bool fHasActiveCons = false;
+
+ if (!g_crvboxhgcm.initialized) return;
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+ fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
+
+#ifndef IN_GUEST
+#else /* IN_GUEST */
+ if (conn->u32ClientID)
+ {
+ int rc = VbglR3HGCMDisconnect(conn->u32ClientID);
+ if (RT_FAILURE(rc))
+ crDebug("Disconnect failed with %Rrc\n", rc);
+ conn->u32ClientID = 0;
+
+ VbglR3Term();
+ }
+#endif /* IN_GUEST */
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+}
+
+static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ _crVBoxHGCMFree(conn, mess);
+ CRASSERT(FALSE);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
+{
+ RT_NOREF(conn, msg, len);
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+ CRASSERT(FALSE);
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+
+bool _crVBoxHGSMIInit()
+{
+#ifndef VBOX_CRHGSMI_WITH_D3DDEV
+ static
+#endif
+ int bHasHGSMI = -1;
+
+ if (bHasHGSMI < 0)
+ {
+ int rc;
+ rc = VBoxCrHgsmiInit();
+ if (RT_SUCCESS(rc))
+ bHasHGSMI = 1;
+ else
+ bHasHGSMI = 0;
+
+ crDebug("CrHgsmi is %s", bHasHGSMI ? "ENABLED" : "DISABLED");
+ }
+
+ CRASSERT(bHasHGSMI >= 0);
+
+ return bHasHGSMI;
+}
+
+void _crVBoxHGSMITearDown()
+{
+ VBoxCrHgsmiTerm();
+}
+
+static void *_crVBoxHGSMIDoAlloc(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
+{
+ PVBOXUHGSMI_BUFFER buf;
+ CRVBOXHGCMBUFFER *pData = NULL;
+ uint32_t cbSize = conn->buffer_size;
+ int rc;
+
+ buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
+ if (buf)
+ {
+ VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+ buf->pvUserData = pClient;
+ fFlags.Value = 0;
+ fFlags.s.fDiscard = 1;
+ rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
+ if (RT_SUCCESS(rc))
+ {
+ pData->magic = CR_VBOXHGCM_BUFFER_MAGIC;
+ pData->kind = CR_VBOXHGCM_UHGSMI_BUFFER;
+ pData->pBuffer = buf;
+ }
+ else
+ {
+ crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
+ }
+ return CRVBOXHGSMI_BUF_DATA(pData);
+ }
+ else
+ {
+ crWarning("_crVBoxHGSMIBufAlloc failed to allocate buffer of size (%d)", CRVBOXHGSMI_BUF_SIZE(cbSize));
+ }
+
+ /* fall back */
+ return _crVBoxHGCMAlloc(conn);
+}
+
+static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
+{
+ CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
+
+ CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
+
+ if (hgcm_buffer->kind == CR_VBOXHGCM_UHGSMI_BUFFER)
+ {
+ PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
+ PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
+ _crVBoxHGSMIBufFree(pClient, pBuf);
+ }
+ else
+ {
+ _crVBoxHGCMFree(conn, buf);
+ }
+}
+
+static void *crVBoxHGSMIAlloc(CRConnection *conn)
+{
+ PCRVBOXHGSMI_CLIENT pClient;
+ void *pvBuf;
+
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ pClient = _crVBoxHGSMIClientGet(conn);
+ if (pClient)
+ {
+ pvBuf = _crVBoxHGSMIDoAlloc(conn, pClient);
+ CRASSERT(pvBuf);
+ }
+ else
+ {
+ pvBuf = _crVBoxHGCMAlloc(conn);
+ }
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+
+ return pvBuf;
+}
+
+static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ _crVBoxHGSMIFree(conn, buf);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
+{
+ CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
+ int rc;
+ VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
+ PVBOXUHGSMI_BUFFER pRecvBuffer;
+ uint32_t cbBuffer;
+
+ CRASSERT(parms);
+
+ parms->hdr.result = VERR_WRONG_ORDER;
+ parms->hdr.u32ClientID = conn->u32ClientID;
+ parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
+/* parms->hdr.u32Reserved = 0;*/
+
+ CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
+ parms->iBuffer = 1;
+ parms->cbBuffer = 0;
+
+ _crVBoxHGSMICmdBufferUnlock(pClient);
+
+ pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
+ CRASSERT(pRecvBuffer);
+ if (!pRecvBuffer)
+ return;
+
+ _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+ aSubmit[1].pBuf = pRecvBuffer;
+ aSubmit[1].offData = 0;
+ aSubmit[1].cbData = pRecvBuffer->cbBuffer;
+ aSubmit[1].fFlags.Value = 0;
+ aSubmit[1].fFlags.s.fHostWriteOnly = 1;
+
+ rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
+ if (RT_FAILURE(rc))
+ {
+ crError("pfnBufferSubmit failed with %d \n", rc);
+ return;
+ }
+
+ parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
+ CRASSERT(parms);
+ if (!parms)
+ {
+ crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
+ return;
+ }
+
+ if (RT_SUCCESS(parms->hdr.result))
+ cbBuffer = parms->cbBuffer;
+ else
+ cbBuffer = 0;
+
+ _crVBoxHGSMICmdBufferUnlock(pClient);
+
+ if (cbBuffer)
+ {
+ void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
+ CRASSERT(pvData);
+ if (pvData)
+ {
+ conn->pBuffer = pvData;
+ conn->cbBuffer = cbBuffer;
+ }
+ }
+}
+
+static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
+{
+ _crVBoxHGSMIPollHost(conn, pClient);
+
+ if (conn->cbBuffer)
+ _crVBoxHGCMReceiveMessage(conn);
+}
+
+/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
+ * This halves the number of HGCM calls we do,
+ * most likely crVBoxHGCMPollHost shouldn't be called at all now.
+ */
+static void
+_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
+{
+ CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
+ int rc;
+ VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
+ PVBOXUHGSMI_BUFFER pBuf = NULL;
+ VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
+/* uint32_t cbBuffer;*/
+
+ parms->hdr.result = VERR_WRONG_ORDER;
+ parms->hdr.u32ClientID = conn->u32ClientID;
+ parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
+/* parms->hdr.u32Reserved = 0;*/
+
+ parms->iBuffer = 1;
+
+ CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
+ parms->iWriteback = 2;
+ parms->cbWriteback = 0;
+
+ _crVBoxHGSMICmdBufferUnlock(pClient);
+
+ if (!bIsBuffer)
+ {
+ void *pvBuf;
+ pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
+
+ if (!pBuf)
+ {
+ /* fallback */
+ crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
+ return;
+ }
+
+ CRASSERT(!offBuffer);
+
+ offBuffer = 0;
+ fFlags.Value = 0;
+ fFlags.s.fDiscard = 1;
+ fFlags.s.fWriteOnly = 1;
+ rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
+ if (RT_SUCCESS(rc))
+ {
+ memcpy(pvBuf, buf, len);
+ rc = pBuf->pfnUnlock(pBuf);
+ CRASSERT(RT_SUCCESS(rc));
+ }
+ else
+ {
+ crWarning("_crVBoxHGSMIWriteReadExact: pfnUnlock failed rc %d", rc);
+ _crVBoxHGSMIBufFree(pClient, pBuf);
+ /* fallback */
+ crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
+ return;
+ }
+ }
+ else
+ {
+ pBuf = (PVBOXUHGSMI_BUFFER)buf;
+ }
+
+ do
+ {
+ PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
+ CRASSERT(pRecvBuffer);
+ if (!pRecvBuffer)
+ {
+ break;
+ }
+
+ _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+ aSubmit[1].pBuf = pBuf;
+ aSubmit[1].offData = offBuffer;
+ aSubmit[1].cbData = len;
+ aSubmit[1].fFlags.Value = 0;
+ aSubmit[1].fFlags.s.fHostReadOnly = 1;
+
+ aSubmit[2].pBuf = pRecvBuffer;
+ aSubmit[2].offData = 0;
+ aSubmit[2].cbData = pRecvBuffer->cbBuffer;
+ aSubmit[2].fFlags.Value = 0;
+
+ rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 3);
+ if (RT_FAILURE(rc))
+ {
+ crError("pfnBufferSubmit failed with %d \n", rc);
+ break;
+ }
+
+ parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
+ CRASSERT(parms);
+ if (parms)
+ {
+ uint32_t cbWriteback = parms->cbWriteback;
+ rc = parms->hdr.result;
+#ifdef DEBUG_misha
+ /* catch it here to test the buffer */
+ Assert(RT_SUCCESS(parms->hdr.Hdr.rc) || parms->hdr.Hdr.rc == VERR_BUFFER_OVERFLOW);
+#endif
+ _crVBoxHGSMICmdBufferUnlock(pClient);
+#ifdef DEBUG
+ parms = NULL;
+#endif
+ if (RT_SUCCESS(rc))
+ {
+ if (cbWriteback)
+ {
+ void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
+ CRASSERT(pvData);
+ if (pvData)
+ {
+ conn->pBuffer = pvData;
+ conn->cbBuffer = cbWriteback;
+ _crVBoxHGCMReceiveMessage(conn);
+ }
+ }
+ }
+ else if (VERR_BUFFER_OVERFLOW == rc)
+ {
+ VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
+ PVBOXUHGSMI_BUFFER pNewBuf;
+ CRASSERT(!pClient->pvHGBuffer);
+ CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
+ crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
+
+ rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pNewBuf);
+ if (RT_SUCCESS(rc))
+ {
+ rc = pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
+ CRASSERT(RT_SUCCESS(rc));
+
+ pClient->pHGBuffer = pNewBuf;
+
+ _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
+ }
+ else
+ {
+ crWarning("_crVBoxHGSMIWriteReadExact: pfnBufferCreate(%d) failed!", CRVBOXHGSMI_PAGE_ALIGN(cbWriteback));
+ if (conn->cbHostBufferAllocated < cbWriteback)
+ {
+ crFree(conn->pHostBuffer);
+ conn->cbHostBufferAllocated = cbWriteback;
+ conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
+ }
+ crVBoxHGCMReadExact(conn, NULL, cbWriteback);
+ }
+ }
+ else
+ {
+ crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
+ }
+ }
+ else
+ {
+ crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
+ break;
+ }
+ } while (0);
+
+ if (!bIsBuffer)
+ _crVBoxHGSMIBufFree(pClient, pBuf);
+
+ return;
+}
+
+static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
+{
+ int rc;
+ int32_t callRes = VINF_SUCCESS; /* Shut up MSC. */
+ VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
+
+#ifdef IN_GUEST
+ if (conn->u32InjectClientID)
+ {
+ CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
+ CRASSERT(parms);
+ if (!parms)
+ {
+ return;
+ }
+
+ parms->hdr.result = VERR_WRONG_ORDER;
+ parms->hdr.u32ClientID = conn->u32ClientID;
+ parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
+/* parms->hdr.u32Reserved = 0;*/
+
+ parms->u32ClientID = conn->u32InjectClientID;
+
+ parms->iBuffer = 1;
+ _crVBoxHGSMICmdBufferUnlock(pClient);
+
+ _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+ aSubmit[1].pBuf = pBuf;
+ aSubmit[1].offData = offStart;
+ aSubmit[1].cbData = len;
+ aSubmit[1].fFlags.Value = 0;
+ aSubmit[1].fFlags.s.fHostReadOnly = 1;
+
+ rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
+ if (RT_SUCCESS(rc))
+ {
+ callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
+ }
+ else
+ {
+ /* we can not recover at this point, report error & exit */
+ crError("pfnBufferSubmit failed with %d \n", rc);
+ }
+ }
+ else
+#endif
+ {
+ CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
+
+ parms->hdr.result = VERR_WRONG_ORDER;
+ parms->hdr.u32ClientID = conn->u32ClientID;
+ parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
+/* parms->hdr.u32Reserved = 0; */
+
+ parms->iBuffer = 1;
+ _crVBoxHGSMICmdBufferUnlock(pClient);
+
+ _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
+
+ aSubmit[1].pBuf = pBuf;
+ aSubmit[1].offData = offStart;
+ aSubmit[1].cbData = len;
+ aSubmit[1].fFlags.Value = 0;
+ aSubmit[1].fFlags.s.fHostReadOnly = 1;
+
+ rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
+ if (RT_SUCCESS(rc))
+ {
+ callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
+ }
+ else
+ {
+ /* we can not recover at this point, report error & exit */
+ crError("Failed to submit CrHhgsmi buffer");
+ }
+ }
+
+ if (RT_FAILURE(rc) || RT_FAILURE(callRes))
+ {
+ crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
+ }
+}
+
+static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
+ const void *start, unsigned int len)
+{
+ PCRVBOXHGSMI_CLIENT pClient;
+ PVBOXUHGSMI_BUFFER pBuf;
+ CRVBOXHGCMBUFFER *hgcm_buffer;
+
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ if (!bufp) /* We're sending a user-allocated buffer. */
+ {
+ pClient = _crVBoxHGSMIClientGet(conn);
+ if (pClient)
+ {
+#ifndef IN_GUEST
+ /** @todo remove temp buffer allocation in unpacker */
+ /* we're at the host side, so just store data until guest polls us */
+ _crVBoxHGCMWriteBytes(conn, start, len);
+#else
+ CRASSERT(!conn->u32InjectClientID);
+ crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
+ _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
+#endif
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return;
+ }
+
+ /* fallback */
+ crVBoxHGCMSend(conn, bufp, start, len);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return;
+ }
+
+ hgcm_buffer = (CRVBOXHGCMBUFFER *) *bufp - 1;
+ CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
+ if (hgcm_buffer->magic != CR_VBOXHGCM_BUFFER_MAGIC)
+ {
+ crError("HGCM buffer magic mismatch");
+ }
+
+
+ if (hgcm_buffer->kind != CR_VBOXHGCM_UHGSMI_BUFFER)
+ {
+ /* fallback */
+ crVBoxHGCMSend(conn, bufp, start, len);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return;
+ }
+
+ /* The region [start .. start + len + 1] lies within a buffer that
+ * was allocated with crVBoxHGCMAlloc() and can be put into the free
+ * buffer pool when we're done sending it.
+ */
+
+ pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
+ CRASSERT(pBuf);
+ if (!pBuf)
+ {
+ crVBoxHGCMSend(conn, bufp, start, len);
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return;
+ }
+
+ pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
+ if (pClient != &conn->HgsmiClient)
+ {
+ crError("HGSMI client mismatch");
+ }
+
+ /* Length would be passed as part of HGCM pointer description
+ * No need to prepend it to the buffer
+ */
+#ifdef IN_GUEST
+ if (conn->u32InjectClientID)
+ {
+ _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
+ }
+ else
+#endif
+ {
+ _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
+ }
+
+ /* Reclaim this pointer for reuse */
+ _crVBoxHGSMIBufFree(pClient, pBuf);
+ /* Since the buffer's now in the 'free' buffer pool, the caller can't
+ * use it any more. Setting bufp to NULL will make sure the caller
+ * doesn't try to re-use the buffer.
+ */
+ *bufp = NULL;
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+ CRASSERT(0);
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+ CRASSERT(0);
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ CRASSERT(0);
+
+ _crVBoxHGCMReceiveMessage(conn);
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+/*
+ * Called on host side only, to "accept" client connection
+ */
+static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+ CRASSERT(0);
+
+ CRASSERT(conn && conn->pHostBuffer);
+#ifdef IN_GUEST
+ CRASSERT(FALSE);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static int crVBoxHGSMIDoConnect( CRConnection *conn )
+{
+ PCRVBOXHGSMI_CLIENT pClient;
+ int rc = VINF_SUCCESS;
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+ pClient = _crVBoxHGSMIClientGet(conn);
+ if (pClient)
+ {
+ rc = VBoxCrHgsmiCtlConGetClientID(pClient->pHgsmi, &conn->u32ClientID);
+ if (RT_FAILURE(rc))
+ {
+ WARN(("VBoxCrHgsmiCtlConGetClientID failed %d", rc));
+ }
+ if (!g_crvboxhgcm.fHostCapsInitialized)
+ {
+ rc = VBoxCrHgsmiCtlConGetHostCaps(pClient->pHgsmi, &g_crvboxhgcm.u32HostCaps);
+ if (RT_SUCCESS(rc))
+ {
+ g_crvboxhgcm.fHostCapsInitialized = true;
+ }
+ else
+ {
+ WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %d", rc));
+ g_crvboxhgcm.u32HostCaps = 0;
+ }
+ }
+ }
+ else
+ {
+ WARN(("_crVBoxHGSMIClientGet failed %d", rc));
+ rc = VERR_GENERAL_FAILURE;
+ }
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ return RT_SUCCESS(rc);
+}
+
+static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
+{
+ bool fHasActiveCons = false;
+
+ if (!g_crvboxhgcm.initialized) return;
+
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
+
+#ifndef VBOX_CRHGSMI_WITH_D3DDEV
+ if (conn->HgsmiClient.pHgsmi)
+ {
+ PVBOXUHGSMI pHgsmi;
+ _crVBoxHGSMIClientTerm(&conn->HgsmiClient, &pHgsmi);
+ CRASSERT(pHgsmi);
+ if (!conn->pExternalHgsmi)
+ VBoxCrHgsmiDestroy(pHgsmi);
+ }
+#else
+# error "port me!"
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+}
+
+static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ CRASSERT(0);
+
+ _crVBoxHGSMIFree(conn, mess);
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+
+static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
+{
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+ CRASSERT(0);
+
+ CRASSERT(FALSE);
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+}
+#endif
+
+void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
+{
+ (void) mtu;
+
+ g_crvboxhgcm.recv_list = rfl;
+ g_crvboxhgcm.close_list = cfl;
+ if (g_crvboxhgcm.initialized)
+ {
+ return;
+ }
+
+ VBOXCRHGSMIPROFILE_INIT();
+
+ g_crvboxhgcm.initialized = 1;
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ g_crvboxhgcm.bHgsmiOn = _crVBoxHGSMIInit();
+#endif
+
+ g_crvboxhgcm.num_conns = 0;
+ g_crvboxhgcm.conns = NULL;
+
+ /* Can't open VBox guest driver here, because it gets called for host side as well */
+ /** @todo as we have 2 dll versions, can do it now.*/
+
+#ifdef RT_OS_WINDOWS
+ g_crvboxhgcm.pDirectDraw = NULL;
+#endif
+
+#ifdef CHROMIUM_THREADSAFE
+ crInitMutex(&g_crvboxhgcm.mutex);
+ crInitMutex(&g_crvboxhgcm.recvmutex);
+#endif
+ g_crvboxhgcm.bufpool = crBufferPoolInit(16);
+
+#ifdef IN_GUEST
+ g_crvboxhgcm.fHostCapsInitialized = false;
+ g_crvboxhgcm.u32HostCaps = 0;
+#endif
+}
+
+/* Callback function used to free buffer pool entries */
+static void crVBoxHGCMBufferFree(void *data)
+{
+ CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
+
+ CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
+
+ switch (hgcm_buffer->kind)
+ {
+ case CR_VBOXHGCM_MEMORY:
+ crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY: %p", hgcm_buffer);
+ crFree( hgcm_buffer );
+ break;
+ case CR_VBOXHGCM_MEMORY_BIG:
+ crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY_BIG: %p", hgcm_buffer);
+ crFree( hgcm_buffer );
+ break;
+
+ default:
+ crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
+ }
+}
+
+void crVBoxHGCMTearDown(void)
+{
+ int32_t i, cCons;
+
+ if (!g_crvboxhgcm.initialized) return;
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
+ * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
+ * order of their connection.
+ */
+ cCons = g_crvboxhgcm.num_conns;
+ for (i=0; i<cCons; i++)
+ {
+ /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
+ crNetDisconnect(g_crvboxhgcm.conns[0]);
+ }
+ CRASSERT(0==g_crvboxhgcm.num_conns);
+
+ g_crvboxhgcm.initialized = 0;
+
+ if (g_crvboxhgcm.bufpool)
+ crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
+ g_crvboxhgcm.bufpool = NULL;
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+ crFreeMutex(&g_crvboxhgcm.mutex);
+ crFreeMutex(&g_crvboxhgcm.recvmutex);
+#endif
+
+ crFree(g_crvboxhgcm.conns);
+ g_crvboxhgcm.conns = NULL;
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ if (g_crvboxhgcm.bHgsmiOn)
+ {
+ _crVBoxHGSMITearDown();
+ }
+#endif
+
+#ifdef RT_OS_WINDOWS
+ if (g_crvboxhgcm.pDirectDraw)
+ {
+ IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
+ g_crvboxhgcm.pDirectDraw = NULL;
+ crDebug("DirectDraw released\n");
+ }
+#endif
+}
+
+void crVBoxHGCMConnection(CRConnection *conn
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ , struct VBOXUHGSMI *pHgsmi
+#endif
+ )
+{
+ int i, found = 0;
+ int n_bytes;
+
+ CRASSERT(g_crvboxhgcm.initialized);
+
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ if (g_crvboxhgcm.bHgsmiOn)
+ {
+ conn->type = CR_VBOXHGCM;
+ conn->Alloc = crVBoxHGSMIAlloc;
+ conn->Send = crVBoxHGSMISend;
+ conn->SendExact = crVBoxHGSMIWriteExact;
+ conn->Recv = crVBoxHGSMISingleRecv;
+ conn->RecvMsg = crVBoxHGSMIReceiveMessage;
+ conn->Free = crVBoxHGSMIFree;
+ conn->Accept = crVBoxHGSMIAccept;
+ conn->Connect = crVBoxHGSMIDoConnect;
+ conn->Disconnect = crVBoxHGSMIDoDisconnect;
+ conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
+ conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
+ conn->pExternalHgsmi = pHgsmi;
+ }
+ else
+#endif
+ {
+ conn->type = CR_VBOXHGCM;
+ conn->Alloc = crVBoxHGCMAlloc;
+ conn->Send = crVBoxHGCMSend;
+ conn->SendExact = crVBoxHGCMWriteExact;
+ conn->Recv = crVBoxHGCMSingleRecv;
+ conn->RecvMsg = crVBoxHGCMReceiveMessage;
+ conn->Free = crVBoxHGCMFree;
+ conn->Accept = crVBoxHGCMAccept;
+ conn->Connect = crVBoxHGCMDoConnect;
+ conn->Disconnect = crVBoxHGCMDoDisconnect;
+ conn->InstantReclaim = crVBoxHGCMInstantReclaim;
+ conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
+ }
+ conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
+ conn->actual_network = 1;
+
+ conn->krecv_buf_size = 0;
+
+ conn->pBuffer = NULL;
+ conn->cbBuffer = 0;
+ conn->allow_redir_ptr = 1;
+
+ /** @todo remove this crap at all later */
+ conn->cbHostBufferAllocated = 2*1024;
+ conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
+ CRASSERT(conn->pHostBuffer);
+ conn->cbHostBuffer = 0;
+
+#if !defined(IN_GUEST)
+ RTListInit(&conn->PendingMsgList);
+#endif
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+ /* Find a free slot */
+ for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
+ if (g_crvboxhgcm.conns[i] == NULL) {
+ conn->index = i;
+ g_crvboxhgcm.conns[i] = conn;
+ found = 1;
+ break;
+ }
+ }
+
+ /* Realloc connection stack if we couldn't find a free slot */
+ if (found == 0) {
+ n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
+ crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
+ conn->index = g_crvboxhgcm.num_conns;
+ g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
+ }
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+}
+
+#if defined(IN_GUEST)
+static void _crVBoxHGCMPerformPollHost(CRConnection *conn)
+{
+ if (conn->type == CR_NO_CONNECTION )
+ return;
+
+ if (!conn->pBuffer)
+ {
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ PCRVBOXHGSMI_CLIENT pClient;
+ if (g_crvboxhgcm.bHgsmiOn && !!(pClient = _crVBoxHGSMIClientGet(conn)))
+ {
+ _crVBoxHGSMIPollHost(conn, pClient);
+ }
+ else
+#endif
+ {
+ crVBoxHGCMPollHost(conn);
+ }
+ }
+}
+#endif
+
+static void _crVBoxHGCMPerformReceiveMessage(CRConnection *conn)
+{
+ if ( conn->type == CR_NO_CONNECTION )
+ return;
+
+ if (conn->cbBuffer>0)
+ {
+ _crVBoxHGCMReceiveMessage(conn);
+ }
+}
+
+#ifdef IN_GUEST
+uint32_t crVBoxHGCMHostCapsGet(void)
+{
+ Assert(g_crvboxhgcm.fHostCapsInitialized);
+ return g_crvboxhgcm.u32HostCaps;
+}
+#endif
+
+int crVBoxHGCMRecv(
+#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ CRConnection *conn
+#else
+ void
+#endif
+ )
+{
+ int32_t i;
+
+ VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
+
+#ifdef CHROMIUM_THREADSAFE
+ crLockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+#ifdef IN_GUEST
+# if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
+ if (conn && g_crvboxhgcm.bHgsmiOn)
+ {
+ _crVBoxHGCMPerformPollHost(conn);
+ _crVBoxHGCMPerformReceiveMessage(conn);
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+ return 0;
+ }
+# endif
+ /* we're on guest side, poll host if it got something for us */
+ for (i=0; i<g_crvboxhgcm.num_conns; i++)
+ {
+ CRConnection *conn = g_crvboxhgcm.conns[i];
+
+ if ( !conn )
+ continue;
+
+ _crVBoxHGCMPerformPollHost(conn);
+ }
+#endif
+
+ for (i=0; i<g_crvboxhgcm.num_conns; i++)
+ {
+ CRConnection *conn = g_crvboxhgcm.conns[i];
+
+ if ( !conn )
+ continue;
+
+ _crVBoxHGCMPerformReceiveMessage(conn);
+ }
+
+#ifdef CHROMIUM_THREADSAFE
+ crUnlockMutex(&g_crvboxhgcm.mutex);
+#endif
+
+ VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
+
+ return 0;
+}
+
+CRConnection** crVBoxHGCMDump( int *num )
+{
+ *num = g_crvboxhgcm.num_conns;
+
+ return g_crvboxhgcm.conns;
+}