44
46
#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
48
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
49
#include <VBox/VBoxCrHgsmi.h>
52
/*@todo move define somewhere else, and make sure it's less than VBGLR0_MAX_HGCM_KERNEL_PARM*/
53
/*If we fail to pass data in one chunk, send it in chunks of this size instead*/
54
#define CR_HGCM_SPLIT_BUFFER_SIZE (8*_1M)
57
# define MIN(a, b) ((a) < (b) ? (a) : (b))
64
#define CRASSERT Assert
67
//#if defined(IN_GUEST)
68
//#define VBOX_WITH_CRHGSMIPROFILE
70
#ifdef VBOX_WITH_CRHGSMIPROFILE
71
#include <iprt/time.h>
74
typedef struct VBOXCRHGSMIPROFILE
79
} VBOXCRHGSMIPROFILE, *PVBOXCRHGSMIPROFILE;
81
#define VBOXCRHGSMIPROFILE_GET_TIME_NANO() RTTimeNanoTS()
82
#define VBOXCRHGSMIPROFILE_GET_TIME_MILLI() RTTimeMilliTS()
85
#define VBOXCRHGSMIPROFILE_LOG_STEP_TIME (10000000000.)
87
DECLINLINE(void) vboxCrHgsmiProfileStart(PVBOXCRHGSMIPROFILE pProfile)
89
pProfile->cStepsTime = 0;
91
pProfile->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
94
DECLINLINE(void) vboxCrHgsmiProfileStep(PVBOXCRHGSMIPROFILE pProfile, uint64_t cStepTime)
96
pProfile->cStepsTime += cStepTime;
100
typedef struct VBOXCRHGSMIPROFILE_SCOPE
104
} VBOXCRHGSMIPROFILE_SCOPE, *PVBOXCRHGSMIPROFILE_SCOPE;
106
static VBOXCRHGSMIPROFILE g_VBoxProfile;
108
static void vboxCrHgsmiLog(char * szString, ...)
110
char szBuffer[4096] = {0};
112
va_start(pArgList, szString);
113
_vsnprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szString, pArgList);
116
#ifdef VBOX_WITH_CRHGSMI
117
VBoxCrHgsmiLog(szBuffer);
119
OutputDebugString(szBuffer);
123
DECLINLINE(void) vboxCrHgsmiProfileLog(PVBOXCRHGSMIPROFILE pProfile, uint64_t cTime)
125
uint64_t profileTime = cTime - pProfile->cStartTime;
126
double percent = ((double)100.0) * pProfile->cStepsTime / profileTime;
127
double cps = ((double)1000000000.) * pProfile->cSteps / profileTime;
128
vboxCrHgsmiLog("hgcm: cps: %.1f, host %.1f%%\n", cps, percent);
131
DECLINLINE(void) vboxCrHgsmiProfileScopeEnter(PVBOXCRHGSMIPROFILE_SCOPE pScope)
133
// pScope->bDisable = false;
134
pScope->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
137
DECLINLINE(void) vboxCrHgsmiProfileScopeExit(PVBOXCRHGSMIPROFILE_SCOPE pScope)
139
// if (!pScope->bDisable)
141
uint64_t cTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
142
vboxCrHgsmiProfileStep(&g_VBoxProfile, cTime - pScope->cStartTime);
143
if (VBOXCRHGSMIPROFILE_LOG_STEP_TIME < cTime - g_VBoxProfile.cStartTime)
145
vboxCrHgsmiProfileLog(&g_VBoxProfile, cTime);
146
vboxCrHgsmiProfileStart(&g_VBoxProfile);
152
#define VBOXCRHGSMIPROFILE_INIT() vboxCrHgsmiProfileStart(&g_VBoxProfile)
153
#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
155
#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() \
156
VBOXCRHGSMIPROFILE_SCOPE __vboxCrHgsmiProfileScope; \
157
vboxCrHgsmiProfileScopeEnter(&__vboxCrHgsmiProfileScope);
159
#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() \
160
vboxCrHgsmiProfileScopeExit(&__vboxCrHgsmiProfileScope); \
164
#define VBOXCRHGSMIPROFILE_INIT() do {} while (0)
165
#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
166
#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() do {} while (0)
167
#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() do {} while (0)
91
231
#define INVALID_HANDLE_VALUE (-1)
235
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
237
/* add sizeof header + page align */
238
#define CRVBOXHGSMI_PAGE_ALIGN(_s) (((_s) + 0xfff) & ~0xfff)
239
#define CRVBOXHGSMI_BUF_HDR_SIZE() (sizeof (CRVBOXHGCMBUFFER))
240
#define CRVBOXHGSMI_BUF_SIZE(_s) CRVBOXHGSMI_PAGE_ALIGN((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
241
#define CRVBOXHGSMI_BUF_LOCK_SIZE(_s) ((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
242
#define CRVBOXHGSMI_BUF_DATA(_p) ((void*)(((CRVBOXHGCMBUFFER*)(_p)) + 1))
243
#define CRVBOXHGSMI_BUF_HDR(_p) (((CRVBOXHGCMBUFFER*)(_p)) - 1)
244
#define CRVBOXHGSMI_BUF_OFFSET(_st2, _st1) ((uint32_t)(((uint8_t*)(_st2)) - ((uint8_t*)(_st1))))
246
static int _crVBoxHGSMIClientInit(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI pHgsmi)
249
pClient->pHgsmi = pHgsmi;
250
rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1),
251
VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT,
253
&pClient->pCmdBuffer);
257
rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1),
258
VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT,
260
&pClient->pHGBuffer);
264
pClient->pvHGBuffer = NULL;
265
pClient->bufpool = crBufferPoolInit(16);
268
pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
270
pClient->pHgsmi = NULL;
274
void _crVBoxHGSMIBufferFree(void *data)
276
PVBOXUHGSMI_BUFFER pBuffer = (PVBOXUHGSMI_BUFFER)data;
277
pBuffer->pfnDestroy(pBuffer);
280
static int _crVBoxHGSMIClientTerm(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI *ppHgsmi)
282
if (pClient->bufpool)
283
crBufferPoolCallbackFree(pClient->bufpool, _crVBoxHGSMIBufferFree);
284
pClient->bufpool = NULL;
286
if (pClient->pHGBuffer)
288
pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
289
pClient->pHGBuffer = NULL;
292
if (pClient->pCmdBuffer)
294
pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
295
pClient->pCmdBuffer = NULL;
300
*ppHgsmi = pClient->pHgsmi;
302
pClient->pHgsmi = NULL;
308
#ifdef VBOX_CRHGSMI_WITH_D3DDEV
310
DECLCALLBACK(HVBOXCRHGSMI_CLIENT) _crVBoxHGSMIClientCreate(PVBOXUHGSMI pHgsmi)
312
PCRVBOXHGSMI_CLIENT pClient = crAlloc(sizeof (CRVBOXHGSMI_CLIENT));
316
int rc = _crVBoxHGSMIClientInit(pClient, pHgsmi);
319
return (HVBOXCRHGSMI_CLIENT)pClient;
327
DECLCALLBACK(void) _crVBoxHGSMIClientDestroy(HVBOXCRHGSMI_CLIENT hClient)
329
PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)hClient;
330
_crVBoxHGSMIClientTerm(pClient, NULL);
335
DECLINLINE(PCRVBOXHGSMI_CLIENT) _crVBoxHGSMIClientGet(CRConnection *conn)
337
#ifdef VBOX_CRHGSMI_WITH_D3DDEV
338
PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)VBoxCrHgsmiQueryClient();
342
if (conn->HgsmiClient.pHgsmi)
343
return &conn->HgsmiClient;
345
PVBOXUHGSMI pHgsmi = VBoxCrHgsmiCreate();
349
int rc = _crVBoxHGSMIClientInit(&conn->HgsmiClient, pHgsmi);
353
Assert(conn->HgsmiClient.pHgsmi);
354
return &conn->HgsmiClient;
356
VBoxCrHgsmiDestroy(pHgsmi);
363
static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
365
PVBOXUHGSMI_BUFFER buf;
368
buf = (PVBOXUHGSMI_BUFFER ) crBufferPoolPop(pClient->bufpool, cbSize);
372
crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
373
(void *) pClient->bufpool,
375
rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, cbSize,
376
VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL,
380
crWarning("Failed to Create a buffer of size(%d), rc(%d)\n", cbSize, rc);
385
static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufFromHdr(CRVBOXHGCMBUFFER *pHdr)
387
PVBOXUHGSMI_BUFFER pBuf;
389
CRASSERT(pHdr->magic == CR_VBOXHGCM_BUFFER_MAGIC);
390
CRASSERT(pHdr->kind == CR_VBOXHGCM_UHGSMI_BUFFER);
391
pBuf = pHdr->pBuffer;
392
rc = pBuf->pfnUnlock(pBuf);
401
static void _crVBoxHGSMIBufFree(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf)
403
crBufferPoolPush(pClient->bufpool, pBuf, pBuf->cbBuffer);
406
static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLock(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
408
/* in theory it is OK to use one cmd buffer for asynch cmd submission
409
* because bDiscard flag should result in allocating a new memory backend if the
410
* allocation is still in use.
411
* However, NOTE: since one and the same semaphore synch event is used for completion notification,
412
* for the notification mechanism working as expected
413
* 1. host must complete commands in the same order as it receives them
414
* (to avoid situation when guest receives notification for another command completion)
415
* 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
416
* 3. guest must wait for command completion in the same order as it submits them
417
* in case we can not satisfy any of the above, we should introduce multiple command buffers */
418
CRVBOXHGSMIHDR * pHdr;
419
VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
423
rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
428
crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
432
static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLockRo(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
434
/* in theory it is OK to use one cmd buffer for asynch cmd submission
435
* because bDiscard flag should result in allocating a new memory backend if the
436
* allocation is still in use.
437
* However, NOTE: since one and the same semaphore synch event is used for completion notification,
438
* for the notification mechanism working as expected
439
* 1. host must complete commands in the same order as it receives them
440
* (to avoid situation when guest receives notification for another command completion)
441
* 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
442
* 3. guest must wait for command completion in the same order as it submits them
443
* in case we can not satisfy any of the above, we should introduce multiple command buffers */
444
CRVBOXHGSMIHDR * pHdr;
445
VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
448
fFlags.bReadOnly = 1;
449
rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
452
crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
456
static void _crVBoxHGSMICmdBufferUnlock(PCRVBOXHGSMI_CLIENT pClient)
458
int rc = pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
461
crWarning("Failed to Unlock the command buffer rc(%d)\n", rc);
464
static int32_t _crVBoxHGSMICmdBufferGetRc(PCRVBOXHGSMI_CLIENT pClient)
466
CRVBOXHGSMIHDR * pHdr;
467
VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
471
fFlags.bReadOnly = 1;
472
rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, sizeof (*pHdr), fFlags, (void**)&pHdr);
476
crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", sizeof (*pHdr), rc);
482
pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
487
DECLINLINE(PVBOXUHGSMI_BUFFER) _crVBoxHGSMIRecvBufGet(PCRVBOXHGSMI_CLIENT pClient)
489
if (pClient->pvHGBuffer)
491
int rc = pClient->pHGBuffer->pfnUnlock(pClient->pHGBuffer);
496
pClient->pvHGBuffer = NULL;
498
return pClient->pHGBuffer;
501
DECLINLINE(void*) _crVBoxHGSMIRecvBufData(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
503
VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
505
Assert(!pClient->pvHGBuffer);
507
rc = pClient->pHGBuffer->pfnLock(pClient->pHGBuffer, 0, cbBuffer, fFlags, &pClient->pvHGBuffer);
511
return pClient->pvHGBuffer;
516
DECLINLINE(void) _crVBoxHGSMIFillCmd(VBOXUHGSMI_BUFFER_SUBMIT *pSubm, PCRVBOXHGSMI_CLIENT pClient, uint32_t cbData)
518
pSubm->pBuf = pClient->pCmdBuffer;
520
pSubm->cbData = cbData;
521
pSubm->fFlags.Value = 0;
522
pSubm->fFlags.bDoNotRetire = 1;
523
// pSubm->fFlags.bDoNotSignalCompletion = 1; /* <- we do not need that actually since
524
// * in case we want completion,
525
// * we will block in _crVBoxHGSMICmdBufferGetRc (when locking the buffer)
526
// * which is needed for getting the result */
530
#define CRVBOXHGSMI_BUF_WAIT(_pBub) WaitForSingleObject((_pBub)->hSynch, INFINITE);
535
DECLINLINE(void) _crVBoxHGSMIWaitCmd(PCRVBOXHGSMI_CLIENT pClient)
537
int rc = CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
94
542
/* Some forward declarations */
95
static void crVBoxHGCMReceiveMessage(CRConnection *conn);
543
static void _crVBoxHGCMReceiveMessage(CRConnection *conn);
98
546
static bool _crVBoxHGCMReadBytes(CRConnection *conn, void *buf, uint32_t len)
900
1579
#endif /* IN_GUEST */
1581
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1583
#ifdef CHROMIUM_THREADSAFE
1584
crUnlockMutex(&g_crvboxhgcm.mutex);
903
1588
static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
905
crVBoxHGCMFree(conn, mess);
1590
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1591
_crVBoxHGCMFree(conn, mess);
906
1592
CRASSERT(FALSE);
1593
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
909
1596
static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1598
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1600
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1603
#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1605
bool _crVBoxHGSMIInit()
1607
#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1615
#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1616
rc = VBoxCrHgsmiInit();
1618
VBOXCRHGSMI_CALLBACKS Callbacks;
1619
Callbacks.pfnClientCreate = _crVBoxHGSMIClientCreate;
1620
Callbacks.pfnClientDestroy = _crVBoxHGSMIClientDestroy;
1621
rc = VBoxCrHgsmiInit(&Callbacks);
1628
crDebug("CrHgsmi is %s", bHasHGSMI ? "ENABLED" : "DISABLED");
1631
Assert(bHasHGSMI >= 0);
1636
void _crVBoxHGSMITearDown()
1641
static void *_crVBoxHGSMIDoAlloc(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1643
PVBOXUHGSMI_BUFFER buf;
1644
CRVBOXHGCMBUFFER *pData = NULL;
1645
uint32_t cbSize = conn->buffer_size;
1648
buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
1652
VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1653
buf->pvUserData = pClient;
1655
fFlags.bDiscard = 1;
1656
rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
1659
pData->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1660
pData->kind = CR_VBOXHGCM_UHGSMI_BUFFER;
1661
pData->pBuffer = buf;
1665
crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
1667
return CRVBOXHGSMI_BUF_DATA(pData);
1671
return _crVBoxHGCMAlloc(conn);
1674
static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
1676
CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1678
CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1680
if (hgcm_buffer->kind == CR_VBOXHGCM_UHGSMI_BUFFER)
1682
PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1683
PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1684
pBuf->pfnUnlock(pBuf);
1685
_crVBoxHGSMIBufFree(pClient, pBuf);
1689
_crVBoxHGCMFree(conn, buf);
1693
static void *crVBoxHGSMIAlloc(CRConnection *conn)
1695
PCRVBOXHGSMI_CLIENT pClient;
1698
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1700
pClient = _crVBoxHGSMIClientGet(conn);
1703
pvBuf = _crVBoxHGSMIDoAlloc(conn, pClient);
1708
pvBuf = _crVBoxHGCMAlloc(conn);
1711
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1716
static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
1718
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1719
_crVBoxHGSMIFree(conn, buf);
1720
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1723
static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1725
CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1727
VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1728
PVBOXUHGSMI_BUFFER pRecvBuffer;
1733
parms->hdr.result = VERR_WRONG_ORDER;
1734
parms->hdr.u32ClientID = conn->u32ClientID;
1735
parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
1736
// parms->hdr.u32Reserved = 0;
1738
CRASSERT(!conn->pBuffer); //make sure there's no data to process
1740
parms->cbBuffer = 0;
1742
_crVBoxHGSMICmdBufferUnlock(pClient);
1744
pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1745
Assert(pRecvBuffer);
1749
_crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1751
aSubmit[1].pBuf = pRecvBuffer;
1752
aSubmit[1].offData = 0;
1753
aSubmit[1].cbData = pRecvBuffer->cbBuffer;
1754
aSubmit[1].fFlags.Value = 0;
1755
aSubmit[1].fFlags.bHostWriteOnly = 1;
1757
rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
1761
crError("pfnBufferSubmitAsynch failed with %d \n", rc);
1765
_crVBoxHGSMIWaitCmd(pClient);
1767
parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1771
crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1775
if (RT_SUCCESS(parms->hdr.result))
1776
cbBuffer = parms->cbBuffer;
1780
_crVBoxHGSMICmdBufferUnlock(pClient);
1784
void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
1788
conn->pBuffer = pvData;
1789
conn->cbBuffer = cbBuffer;
1794
static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1796
_crVBoxHGSMIPollHost(conn, pClient);
1799
_crVBoxHGCMReceiveMessage(conn);
1802
/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
1803
* This halves the number of HGCM calls we do,
1804
* most likely crVBoxHGCMPollHost shouldn't be called at all now.
1807
_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
1809
CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1811
VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
1812
PVBOXUHGSMI_BUFFER pBuf = NULL;
1813
VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1814
// uint32_t cbBuffer;
1816
parms->hdr.result = VERR_WRONG_ORDER;
1817
parms->hdr.u32ClientID = conn->u32ClientID;
1818
parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
1819
// parms->hdr.u32Reserved = 0;
1823
CRASSERT(!conn->pBuffer); //make sure there's no data to process
1824
parms->iWriteback = 2;
1825
parms->cbWriteback = 0;
1827
_crVBoxHGSMICmdBufferUnlock(pClient);
1832
pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
1837
crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1845
fFlags.bDiscard = 1;
1846
fFlags.bWriteOnly = 1;
1847
rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
1851
memcpy(pvBuf, buf, len);
1852
rc = pBuf->pfnUnlock(pBuf);
1854
CRASSERT(RT_SUCCESS(rc));
1858
_crVBoxHGSMIBufFree(pClient, pBuf);
1860
crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1866
pBuf = (PVBOXUHGSMI_BUFFER)buf;
1871
PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1872
Assert(pRecvBuffer);
1878
_crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1880
aSubmit[1].pBuf = pBuf;
1881
aSubmit[1].offData = offBuffer;
1882
aSubmit[1].cbData = len;
1883
aSubmit[1].fFlags.Value = 0;
1884
aSubmit[1].fFlags.bHostReadOnly = 1;
1886
aSubmit[2].pBuf = pRecvBuffer;
1887
aSubmit[2].offData = 0;
1888
aSubmit[2].cbData = pRecvBuffer->cbBuffer;
1889
aSubmit[2].fFlags.Value = 0;
1891
rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 3);
1895
crError("pfnBufferSubmitAsynch failed with %d \n", rc);
1899
_crVBoxHGSMIWaitCmd(pClient);
1901
parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1905
uint32_t cbWriteback = parms->cbWriteback;
1906
rc = parms->hdr.result;
1907
_crVBoxHGSMICmdBufferUnlock(pClient);
1915
void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
1919
conn->pBuffer = pvData;
1920
conn->cbBuffer = cbWriteback;
1921
_crVBoxHGCMReceiveMessage(conn);
1925
else if (VERR_BUFFER_OVERFLOW == rc)
1927
PVBOXUHGSMI_BUFFER pOldBuf = pClient->pHGBuffer;
1928
Assert(!pClient->pvHGBuffer);
1929
CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
1930
crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
1932
rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback),
1933
VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL, &pClient->pHGBuffer);
1935
CRASSERT(RT_SUCCESS(rc));
1938
rc = pOldBuf->pfnDestroy(pOldBuf);
1939
CRASSERT(RT_SUCCESS(rc));
1941
_crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
1945
crFree(conn->pHostBuffer);
1946
conn->cbHostBufferAllocated = cbWriteback;
1947
conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
1948
crVBoxHGCMReadExact(conn, NULL, cbWriteback);
1953
crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
1958
crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1964
_crVBoxHGSMIBufFree(pClient, pBuf);
1969
static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
1973
VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1976
if (conn->u32InjectClientID)
1978
CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1985
parms->hdr.result = VERR_WRONG_ORDER;
1986
parms->hdr.u32ClientID = conn->u32ClientID;
1987
parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
1988
// parms->hdr.u32Reserved = 0;
1990
parms->u32ClientID = conn->u32InjectClientID;
1993
_crVBoxHGSMICmdBufferUnlock(pClient);
1995
_crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1997
aSubmit[1].pBuf = pBuf;
1998
aSubmit[1].offData = offStart;
1999
aSubmit[1].cbData = len;
2000
aSubmit[1].fFlags.Value = 0;
2001
aSubmit[1].fFlags.bHostReadOnly = 1;
2003
rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
2007
_crVBoxHGSMIWaitCmd(pClient);
2008
/* @todo: do we need to wait for completion actually?
2009
* NOTE: in case we do not need completion,
2010
* we MUST specify bDoNotSignalCompletion flag for the command buffer */
2011
// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
2013
callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
2017
/* we can not recover at this point, report error & exit */
2018
crError("pfnBufferSubmitAsynch failed with %d \n", rc);
2024
CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
2026
parms->hdr.result = VERR_WRONG_ORDER;
2027
parms->hdr.u32ClientID = conn->u32ClientID;
2028
parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
2029
// parms->hdr.u32Reserved = 0;
2032
_crVBoxHGSMICmdBufferUnlock(pClient);
2034
_crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
2036
aSubmit[1].pBuf = pBuf;
2037
aSubmit[1].offData = offStart;
2038
aSubmit[1].cbData = len;
2039
aSubmit[1].fFlags.Value = 0;
2040
aSubmit[1].fFlags.bHostReadOnly = 1;
2042
rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
2046
_crVBoxHGSMIWaitCmd(pClient);
2047
/* @todo: do we need to wait for completion actually?
2048
* NOTE: in case we do not need completion,
2049
* we MUST specify bDoNotSignalCompletion flag for the command buffer */
2050
// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
2052
callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
2056
/* we can not recover at this point, report error & exit */
2057
crError("Failed to submit CrHhgsmi buffer");
2061
if (RT_FAILURE(rc) || RT_FAILURE(callRes))
2063
crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
2067
static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
2068
const void *start, unsigned int len)
2070
PCRVBOXHGSMI_CLIENT pClient;
2071
PVBOXUHGSMI_BUFFER pBuf;
2072
CRVBOXHGCMBUFFER *hgcm_buffer;
2074
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2076
if (!bufp) /* We're sending a user-allocated buffer. */
2078
pClient = _crVBoxHGSMIClientGet(conn);
2082
//@todo remove temp buffer allocation in unpacker
2083
/* we're at the host side, so just store data until guest polls us */
2084
_crVBoxHGCMWriteBytes(conn, start, len);
2086
CRASSERT(!conn->u32InjectClientID);
2087
crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
2088
_crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
2090
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2095
crVBoxHGCMSend(conn, bufp, start, len);
2096
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2100
hgcm_buffer = (CRVBOXHGCMBUFFER *) *bufp - 1;
2101
Assert(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2102
if (hgcm_buffer->kind != CR_VBOXHGCM_UHGSMI_BUFFER)
2105
crVBoxHGCMSend(conn, bufp, start, len);
2106
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2110
/* The region [start .. start + len + 1] lies within a buffer that
2111
* was allocated with crVBoxHGCMAlloc() and can be put into the free
2112
* buffer pool when we're done sending it.
2115
pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
2119
crVBoxHGCMSend(conn, bufp, start, len);
2120
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2124
pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
2126
/* Length would be passed as part of HGCM pointer description
2127
* No need to prepend it to the buffer
2130
if (conn->u32InjectClientID)
2132
_crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
2137
_crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
2140
/* Reclaim this pointer for reuse */
2141
_crVBoxHGSMIBufFree(pClient, pBuf);
2142
/* Since the buffer's now in the 'free' buffer pool, the caller can't
2143
* use it any more. Setting bufp to NULL will make sure the caller
2144
* doesn't try to re-use the buffer.
2148
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2151
static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
2153
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2157
// PCRVBOXHGSMI_CLIENT pClient;
2158
// PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
2161
// pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
2162
// _crVBoxHGSMIWriteExact(conn, pClient, pBuf, 0, len);
2163
// _crVBoxHGSMIBufFree(pClient, pBuf);
2164
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2167
static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
2169
// PCRVBOXHGSMI_CLIENT pClient;
2170
// PVBOXUHGSMI_BUFFER pBuf;
2171
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2172
// pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
2178
// VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2181
// pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
2182
// _crVBoxHGSMIReadExact(conn, pClient);
2183
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2186
static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
2188
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2192
_crVBoxHGCMReceiveMessage(conn);
2193
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2197
* Called on host side only, to "accept" client connection
2199
static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
2201
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2204
CRASSERT(conn && conn->pHostBuffer);
2208
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2211
static int crVBoxHGSMIDoConnect( CRConnection *conn )
2213
return crVBoxHGCMDoConnect(conn);
2216
static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
2218
#ifndef VBOX_CRHGSMI_WITH_D3DDEV
2219
if (conn->HgsmiClient.pHgsmi)
2222
_crVBoxHGSMIClientTerm(&conn->HgsmiClient, &pHgsmi);
2224
VBoxCrHgsmiDestroy(pHgsmi);
2228
crVBoxHGCMDoDisconnect(conn);
2231
static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
2233
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2236
_crVBoxHGSMIFree(conn, mess);
2239
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2242
static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
2244
VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2248
VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
914
2252
void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)