VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/vboxhgcm.c@ 33988

Last change on this file since 33988 was 33988, checked in by vboxsync, 14 years ago

crOpenGL/wddm: more multithreading fixes, vista expirience index works now

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 69.7 KB
Line 
1/* $Id: vboxhgcm.c 33988 2010-11-11 13:03:17Z vboxsync $ */
2
3/** @file
4 * VBox HGCM connection
5 */
6
7/*
8 * Copyright (C) 2008 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18#ifdef RT_OS_WINDOWS
19 #include <windows.h>
20 #include <ddraw.h>
21#else
22 #include <sys/ioctl.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <unistd.h>
27#endif
28
29#include "cr_error.h"
30#include "cr_net.h"
31#include "cr_bufpool.h"
32#include "cr_mem.h"
33#include "cr_string.h"
34#include "cr_endian.h"
35#include "cr_threads.h"
36#include "net_internals.h"
37#include "cr_process.h"
38
39#include <iprt/thread.h>
40
41#if 1 /** @todo Try use the Vbgl interface instead of talking directly to the driver? */
42# include <VBox/VBoxGuest.h>
43#else
44# include <VBox/VBoxGuestLib.h>
45#endif
46#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
47
48#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
49#include <VBox/VBoxCrHgsmi.h>
50#endif
51
52#ifdef DEBUG_misha
53#ifdef CRASSERT
54# undef CRASSERT
55#endif
56#define CRASSERT Assert
57#endif
58//#define IN_GUEST
59//#if defined(IN_GUEST)
60//#define VBOX_WITH_CRHGSMIPROFILE
61//#endif
62#ifdef VBOX_WITH_CRHGSMIPROFILE
63#include <iprt/time.h>
64#include <stdio.h>
65
66typedef struct VBOXCRHGSMIPROFILE
67{
68 uint64_t cStartTime;
69 uint64_t cStepsTime;
70 uint64_t cSteps;
71} VBOXCRHGSMIPROFILE, *PVBOXCRHGSMIPROFILE;
72
73#define VBOXCRHGSMIPROFILE_GET_TIME_NANO() RTTimeNanoTS()
74#define VBOXCRHGSMIPROFILE_GET_TIME_MILLI() RTTimeMilliTS()
75
76/* 10 sec */
77#define VBOXCRHGSMIPROFILE_LOG_STEP_TIME (10000000000.)
78
79DECLINLINE(void) vboxCrHgsmiProfileStart(PVBOXCRHGSMIPROFILE pProfile)
80{
81 pProfile->cStepsTime = 0;
82 pProfile->cSteps = 0;
83 pProfile->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
84}
85
86DECLINLINE(void) vboxCrHgsmiProfileStep(PVBOXCRHGSMIPROFILE pProfile, uint64_t cStepTime)
87{
88 pProfile->cStepsTime += cStepTime;
89 ++pProfile->cSteps;
90}
91
92typedef struct VBOXCRHGSMIPROFILE_SCOPE
93{
94 uint64_t cStartTime;
95// bool bDisable;
96} VBOXCRHGSMIPROFILE_SCOPE, *PVBOXCRHGSMIPROFILE_SCOPE;
97
98static VBOXCRHGSMIPROFILE g_VBoxProfile;
99
100static void vboxCrHgsmiLog(char * szString, ...)
101{
102 char szBuffer[4096] = {0};
103 va_list pArgList;
104 va_start(pArgList, szString);
105 _vsnprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szString, pArgList);
106 va_end(pArgList);
107
108#ifdef VBOX_WITH_CRHGSMI
109 VBoxCrHgsmiLog(szBuffer);
110#else
111 OutputDebugString(szBuffer);
112#endif
113}
114
115DECLINLINE(void) vboxCrHgsmiProfileLog(PVBOXCRHGSMIPROFILE pProfile, uint64_t cTime)
116{
117 uint64_t profileTime = cTime - pProfile->cStartTime;
118 double percent = ((double)100.0) * pProfile->cStepsTime / profileTime;
119 double cps = ((double)1000000000.) * pProfile->cSteps / profileTime;
120 vboxCrHgsmiLog("hgcm: cps: %.1f, host %.1f%%\n", cps, percent);
121}
122
123DECLINLINE(void) vboxCrHgsmiProfileScopeEnter(PVBOXCRHGSMIPROFILE_SCOPE pScope)
124{
125// pScope->bDisable = false;
126 pScope->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
127}
128
129DECLINLINE(void) vboxCrHgsmiProfileScopeExit(PVBOXCRHGSMIPROFILE_SCOPE pScope)
130{
131// if (!pScope->bDisable)
132 {
133 uint64_t cTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
134 vboxCrHgsmiProfileStep(&g_VBoxProfile, cTime - pScope->cStartTime);
135 if (VBOXCRHGSMIPROFILE_LOG_STEP_TIME < cTime - g_VBoxProfile.cStartTime)
136 {
137 vboxCrHgsmiProfileLog(&g_VBoxProfile, cTime);
138 vboxCrHgsmiProfileStart(&g_VBoxProfile);
139 }
140 }
141}
142
143
144#define VBOXCRHGSMIPROFILE_INIT() vboxCrHgsmiProfileStart(&g_VBoxProfile)
145#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
146
147#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() \
148 VBOXCRHGSMIPROFILE_SCOPE __vboxCrHgsmiProfileScope; \
149 vboxCrHgsmiProfileScopeEnter(&__vboxCrHgsmiProfileScope);
150
151#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() \
152 vboxCrHgsmiProfileScopeExit(&__vboxCrHgsmiProfileScope); \
153
154
155#else
156#define VBOXCRHGSMIPROFILE_INIT() do {} while (0)
157#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
158#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() do {} while (0)
159#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() do {} while (0)
160#endif
161
162typedef struct {
163 int initialized;
164 int num_conns;
165 CRConnection **conns;
166 CRBufferPool *bufpool;
167#ifdef CHROMIUM_THREADSAFE
168 CRmutex mutex;
169 CRmutex recvmutex;
170#endif
171 CRNetReceiveFuncList *recv_list;
172 CRNetCloseFuncList *close_list;
173#ifdef RT_OS_WINDOWS
174 HANDLE hGuestDrv;
175 LPDIRECTDRAW pDirectDraw;
176#else
177 int iGuestDrv;
178#endif
179#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
180 bool bHgsmiOn;
181#endif
182} CRVBOXHGCMDATA;
183
184static CRVBOXHGCMDATA g_crvboxhgcm = {0,};
185
186typedef enum {
187 CR_VBOXHGCM_USERALLOCATED,
188 CR_VBOXHGCM_MEMORY,
189 CR_VBOXHGCM_MEMORY_BIG
190#ifdef RT_OS_WINDOWS
191 ,CR_VBOXHGCM_DDRAW_SURFACE
192#endif
193#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
194 ,CR_VBOXHGCM_UHGSMI_BUFFER
195#endif
196} CRVBOXHGCMBUFFERKIND;
197
198#define CR_VBOXHGCM_BUFFER_MAGIC 0xABCDE321
199
200typedef struct CRVBOXHGCMBUFFER {
201 uint32_t magic;
202 CRVBOXHGCMBUFFERKIND kind;
203 union
204 {
205 struct
206 {
207 uint32_t len;
208 uint32_t allocated;
209 };
210
211#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
212 PVBOXUHGSMI_BUFFER pBuffer;
213#endif
214 };
215#ifdef RT_OS_WINDOWS
216 LPDIRECTDRAWSURFACE pDDS;
217#endif
218} CRVBOXHGCMBUFFER;
219
220#ifndef RT_OS_WINDOWS
221 #define TRUE true
222 #define FALSE false
223 #define INVALID_HANDLE_VALUE (-1)
224#endif
225
226
227#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
228
229/* add sizeof header + page align */
230#define CRVBOXHGSMI_PAGE_ALIGN(_s) (((_s) + 0xfff) & ~0xfff)
231#define CRVBOXHGSMI_BUF_HDR_SIZE() (sizeof (CRVBOXHGCMBUFFER))
232#define CRVBOXHGSMI_BUF_SIZE(_s) CRVBOXHGSMI_PAGE_ALIGN((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
233#define CRVBOXHGSMI_BUF_LOCK_SIZE(_s) ((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
234#define CRVBOXHGSMI_BUF_DATA(_p) ((void*)(((CRVBOXHGCMBUFFER*)(_p)) + 1))
235#define CRVBOXHGSMI_BUF_HDR(_p) (((CRVBOXHGCMBUFFER*)(_p)) - 1)
236#define CRVBOXHGSMI_BUF_OFFSET(_st2, _st1) ((uint32_t)(((uint8_t*)(_st2)) - ((uint8_t*)(_st1))))
237
238static int _crVBoxHGSMIClientInit(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI pHgsmi)
239{
240 int rc;
241 pClient->pHgsmi = pHgsmi;
242 rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1),
243 VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT,
244 NULL,
245 &pClient->pCmdBuffer);
246 AssertRC(rc);
247 if (RT_SUCCESS(rc))
248 {
249 rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1),
250 VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT,
251 NULL,
252 &pClient->pHGBuffer);
253 AssertRC(rc);
254 if (RT_SUCCESS(rc))
255 {
256 pClient->pvHGBuffer = NULL;
257 pClient->bufpool = crBufferPoolInit(16);
258 return VINF_SUCCESS;
259 }
260 pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
261 }
262 pClient->pHgsmi = NULL;
263 return rc;
264}
265
266void _crVBoxHGSMIBufferFree(void *data)
267{
268 PVBOXUHGSMI_BUFFER pBuffer = (PVBOXUHGSMI_BUFFER)data;
269 pBuffer->pfnDestroy(pBuffer);
270}
271
272static int _crVBoxHGSMIClientTerm(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI *ppHgsmi)
273{
274 if (pClient->bufpool)
275 crBufferPoolCallbackFree(pClient->bufpool, _crVBoxHGSMIBufferFree);
276 pClient->bufpool = NULL;
277
278 if (pClient->pHGBuffer)
279 {
280 pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
281 pClient->pHGBuffer = NULL;
282 }
283
284 if (pClient->pCmdBuffer)
285 {
286 pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
287 pClient->pCmdBuffer = NULL;
288 }
289
290 if (ppHgsmi)
291 {
292 *ppHgsmi = pClient->pHgsmi;
293 }
294 pClient->pHgsmi = NULL;
295
296 return VINF_SUCCESS;
297}
298
299
300#ifdef VBOX_CRHGSMI_WITH_D3DDEV
301
302DECLCALLBACK(HVBOXCRHGSMI_CLIENT) _crVBoxHGSMIClientCreate(PVBOXUHGSMI pHgsmi)
303{
304 PCRVBOXHGSMI_CLIENT pClient = crAlloc(sizeof (CRVBOXHGSMI_CLIENT));
305
306 if (pClient)
307 {
308 int rc = _crVBoxHGSMIClientInit(pClient, pHgsmi);
309 AssertRC(rc);
310 if (RT_SUCCESS(rc))
311 return (HVBOXCRHGSMI_CLIENT)pClient;
312
313 crFree(pCLient);
314 }
315
316 return NULL;
317}
318
319DECLCALLBACK(void) _crVBoxHGSMIClientDestroy(HVBOXCRHGSMI_CLIENT hClient)
320{
321 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)hClient;
322 _crVBoxHGSMIClientTerm(pClient, NULL);
323 crFree(pClient);
324}
325#endif
326
327DECLINLINE(PCRVBOXHGSMI_CLIENT) _crVBoxHGSMIClientGet(CRConnection *conn)
328{
329#ifdef VBOX_CRHGSMI_WITH_D3DDEV
330 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)VBoxCrHgsmiQueryClient();
331 Assert(pClient);
332 return pClient;
333#else
334 if (conn->HgsmiClient.pHgsmi)
335 return &conn->HgsmiClient;
336 {
337 PVBOXUHGSMI pHgsmi = VBoxCrHgsmiCreate();
338 Assert(pHgsmi);
339 if (pHgsmi)
340 {
341 int rc = _crVBoxHGSMIClientInit(&conn->HgsmiClient, pHgsmi);
342 AssertRC(rc);
343 if (RT_SUCCESS(rc))
344 {
345 Assert(conn->HgsmiClient.pHgsmi);
346 return &conn->HgsmiClient;
347 }
348 VBoxCrHgsmiDestroy(pHgsmi);
349 }
350 }
351 return NULL;
352#endif
353}
354
355static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
356{
357 PVBOXUHGSMI_BUFFER buf;
358 int rc;
359
360 buf = (PVBOXUHGSMI_BUFFER ) crBufferPoolPop(pClient->bufpool, cbSize);
361
362 if (!buf)
363 {
364 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
365 (void *) pClient->bufpool,
366 cbSize);
367 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, cbSize,
368 VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL,
369 &buf);
370 AssertRC(rc);
371 if (RT_FAILURE(rc))
372 crWarning("Failed to Create a buffer of size(%d), rc(%d)\n", cbSize, rc);
373 }
374 return buf;
375}
376
377static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufFromHdr(CRVBOXHGCMBUFFER *pHdr)
378{
379 PVBOXUHGSMI_BUFFER pBuf;
380 int rc;
381 CRASSERT(pHdr->magic == CR_VBOXHGCM_BUFFER_MAGIC);
382 CRASSERT(pHdr->kind == CR_VBOXHGCM_UHGSMI_BUFFER);
383 pBuf = pHdr->pBuffer;
384 rc = pBuf->pfnUnlock(pBuf);
385 AssertRC(rc);
386 if (RT_FAILURE(rc))
387 {
388 return NULL;
389 }
390 return pBuf;
391}
392
393static void _crVBoxHGSMIBufFree(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf)
394{
395 crBufferPoolPush(pClient->bufpool, pBuf, pBuf->cbBuffer);
396}
397
398static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLock(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
399{
400 /* in theory it is OK to use one cmd buffer for asynch cmd submission
401 * because bDiscard flag should result in allocating a new memory backend if the
402 * allocation is still in use.
403 * However, NOTE: since one and the same semaphore synch event is used for completion notification,
404 * for the notification mechanism working as expected
405 * 1. host must complete commands in the same order as it receives them
406 * (to avoid situation when guest receives notification for another command completion)
407 * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
408 * 3. guest must wait for command completion in the same order as it submits them
409 * in case we can not satisfy any of the above, we should introduce multiple command buffers */
410 CRVBOXHGSMIHDR * pHdr;
411 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
412 int rc;
413 fFlags.Value = 0;
414 fFlags.bDiscard = 1;
415 rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
416 AssertRC(rc);
417 if (RT_SUCCESS(rc))
418 return pHdr;
419
420 crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
421 return NULL;
422}
423
424static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLockRo(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
425{
426 /* in theory it is OK to use one cmd buffer for asynch cmd submission
427 * because bDiscard flag should result in allocating a new memory backend if the
428 * allocation is still in use.
429 * However, NOTE: since one and the same semaphore synch event is used for completion notification,
430 * for the notification mechanism working as expected
431 * 1. host must complete commands in the same order as it receives them
432 * (to avoid situation when guest receives notification for another command completion)
433 * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
434 * 3. guest must wait for command completion in the same order as it submits them
435 * in case we can not satisfy any of the above, we should introduce multiple command buffers */
436 CRVBOXHGSMIHDR * pHdr;
437 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
438 int rc;
439 fFlags.Value = 0;
440 fFlags.bReadOnly = 1;
441 rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
442 AssertRC(rc);
443 if (RT_FAILURE(rc))
444 crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
445 return pHdr;
446}
447
448static void _crVBoxHGSMICmdBufferUnlock(PCRVBOXHGSMI_CLIENT pClient)
449{
450 int rc = pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
451 AssertRC(rc);
452 if (RT_FAILURE(rc))
453 crWarning("Failed to Unlock the command buffer rc(%d)\n", rc);
454}
455
456static int32_t _crVBoxHGSMICmdBufferGetRc(PCRVBOXHGSMI_CLIENT pClient)
457{
458 CRVBOXHGSMIHDR * pHdr;
459 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
460 int rc;
461
462 fFlags.Value = 0;
463 fFlags.bReadOnly = 1;
464 rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, sizeof (*pHdr), fFlags, (void**)&pHdr);
465 AssertRC(rc);
466 if (RT_FAILURE(rc))
467 {
468 crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", sizeof (*pHdr), rc);
469 return rc;
470 }
471
472 rc = pHdr->result;
473 AssertRC(rc);
474 pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
475
476 return rc;
477}
478
479DECLINLINE(PVBOXUHGSMI_BUFFER) _crVBoxHGSMIRecvBufGet(PCRVBOXHGSMI_CLIENT pClient)
480{
481 if (pClient->pvHGBuffer)
482 {
483 int rc = pClient->pHGBuffer->pfnUnlock(pClient->pHGBuffer);
484 if (RT_FAILURE(rc))
485 {
486 return NULL;
487 }
488 pClient->pvHGBuffer = NULL;
489 }
490 return pClient->pHGBuffer;
491}
492
493DECLINLINE(void*) _crVBoxHGSMIRecvBufData(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
494{
495 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
496 int rc;
497 Assert(!pClient->pvHGBuffer);
498 fFlags.Value = 0;
499 rc = pClient->pHGBuffer->pfnLock(pClient->pHGBuffer, 0, cbBuffer, fFlags, &pClient->pvHGBuffer);
500 AssertRC(rc);
501 if (RT_SUCCESS(rc))
502 {
503 return pClient->pvHGBuffer;
504 }
505 return NULL;
506}
507
508DECLINLINE(void) _crVBoxHGSMIFillCmd(VBOXUHGSMI_BUFFER_SUBMIT *pSubm, PCRVBOXHGSMI_CLIENT pClient, uint32_t cbData)
509{
510 pSubm->pBuf = pClient->pCmdBuffer;
511 pSubm->offData = 0;
512 pSubm->cbData = cbData;
513 pSubm->fFlags.Value = 0;
514 pSubm->fFlags.bDoNotRetire = 1;
515// pSubm->fFlags.bDoNotSignalCompletion = 1; /* <- we do not need that actually since
516// * in case we want completion,
517// * we will block in _crVBoxHGSMICmdBufferGetRc (when locking the buffer)
518// * which is needed for getting the result */
519}
520
521#ifdef RT_OS_WINDOWS
522#define CRVBOXHGSMI_BUF_WAIT(_pBub) WaitForSingleObject((_pBub)->hSynch, INFINITE);
523#else
524# error "Port Me!!"
525#endif
526
527DECLINLINE(void) _crVBoxHGSMIWaitCmd(PCRVBOXHGSMI_CLIENT pClient)
528{
529 int rc = CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
530 Assert(rc == 0);
531}
532#endif
533
534/* Some forward declarations */
535static void _crVBoxHGCMReceiveMessage(CRConnection *conn);
536
537#ifndef IN_GUEST
538static bool _crVBoxHGCMReadBytes(CRConnection *conn, void *buf, uint32_t len)
539{
540 CRASSERT(conn && buf);
541
542 if (!conn->pBuffer || (conn->cbBuffer<len))
543 return FALSE;
544
545 crMemcpy(buf, conn->pBuffer, len);
546
547 conn->cbBuffer -= len;
548 conn->pBuffer = conn->cbBuffer>0 ? (uint8_t*)conn->pBuffer+len : NULL;
549
550 return TRUE;
551}
552#endif
553
554/*@todo get rid of it*/
555static bool _crVBoxHGCMWriteBytes(CRConnection *conn, const void *buf, uint32_t len)
556{
557 CRASSERT(conn && buf);
558
559 /* make sure there's host buffer and it's clear */
560 CRASSERT(conn->pHostBuffer && !conn->cbHostBuffer);
561
562 if (conn->cbHostBufferAllocated < len)
563 {
564 crDebug("Host buffer too small %d out of requested %d bytes, reallocating", conn->cbHostBufferAllocated, len);
565 crFree(conn->pHostBuffer);
566 conn->pHostBuffer = crAlloc(len);
567 if (!conn->pHostBuffer)
568 {
569 conn->cbHostBufferAllocated = 0;
570 crError("OUT_OF_MEMORY trying to allocate %d bytes", len);
571 return FALSE;
572 }
573 conn->cbHostBufferAllocated = len;
574 }
575
576 crMemcpy(conn->pHostBuffer, buf, len);
577 conn->cbHostBuffer = len;
578
579 return TRUE;
580}
581
582/**
583 * Send an HGCM request
584 *
585 * @return VBox status code
586 * @param pvData Data pointer
587 * @param cbData Data size
588 */
589/** @todo use vbglR3DoIOCtl here instead */
590static int crVBoxHGCMCall(void *pvData, unsigned cbData)
591{
592#ifdef IN_GUEST
593
594# ifdef RT_OS_WINDOWS
595 DWORD cbReturned;
596
597 if (DeviceIoControl (g_crvboxhgcm.hGuestDrv,
598 VBOXGUEST_IOCTL_HGCM_CALL(cbData),
599 pvData, cbData,
600 pvData, cbData,
601 &cbReturned,
602 NULL))
603 {
604 return VINF_SUCCESS;
605 }
606 crDebug("vboxCall failed with %x\n", GetLastError());
607 return VERR_NOT_SUPPORTED;
608# else
609 int rc;
610# if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
611 VBGLBIGREQ Hdr;
612 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
613 Hdr.cbData = cbData;
614 Hdr.pvDataR3 = pvData;
615# if HC_ARCH_BITS == 32
616 Hdr.u32Padding = 0;
617# endif
618 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), &Hdr);
619# else
620 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
621# endif
622# ifdef RT_OS_LINUX
623 if (rc == 0)
624# else
625 if (rc >= 0)
626# endif
627 {
628 return VINF_SUCCESS;
629 }
630# ifdef RT_OS_LINUX
631 if (rc >= 0) /* positive values are negated VBox error status codes. */
632 {
633 crWarning("vboxCall failed with VBox status code %d\n", -rc);
634 if (rc==VINF_INTERRUPTED)
635 {
636 RTMSINTERVAL sl;
637 int i;
638
639 for (i=0, sl=50; i<6; i++, sl=sl*2)
640 {
641 RTThreadSleep(sl);
642 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
643 if (rc==0)
644 {
645 crWarning("vboxCall retry(%i) succeeded", i+1);
646 return VINF_SUCCESS;
647 }
648 else if (rc==VINF_INTERRUPTED)
649 {
650 continue;
651 }
652 else
653 {
654 crWarning("vboxCall retry(%i) failed with VBox status code %d", i+1, -rc);
655 break;
656 }
657 }
658 }
659 }
660 else
661# endif
662 crWarning("vboxCall failed with %x\n", errno);
663 return VERR_NOT_SUPPORTED;
664# endif /*#ifdef RT_OS_WINDOWS*/
665
666#else /*#ifdef IN_GUEST*/
667 crError("crVBoxHGCMCall called on host side!");
668 CRASSERT(FALSE);
669 return VERR_NOT_SUPPORTED;
670#endif
671}
672
673static void *_crVBoxHGCMAlloc(CRConnection *conn)
674{
675 CRVBOXHGCMBUFFER *buf;
676
677#ifdef CHROMIUM_THREADSAFE
678 crLockMutex(&g_crvboxhgcm.mutex);
679#endif
680
681 buf = (CRVBOXHGCMBUFFER *) crBufferPoolPop(g_crvboxhgcm.bufpool, conn->buffer_size);
682
683 if (!buf)
684 {
685 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
686 (void *) g_crvboxhgcm.bufpool,
687 (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
688
689#if defined(IN_GUEST) && defined(RT_OS_WINDOWS)
690 /* Try to start DDRAW on guest side */
691 if (!g_crvboxhgcm.pDirectDraw && 0)
692 {
693 HRESULT hr;
694
695 hr = DirectDrawCreate(NULL, &g_crvboxhgcm.pDirectDraw, NULL);
696 if (hr != DD_OK)
697 {
698 crWarning("Failed to create DirectDraw interface (%x)\n", hr);
699 g_crvboxhgcm.pDirectDraw = NULL;
700 }
701 else
702 {
703 hr = IDirectDraw_SetCooperativeLevel(g_crvboxhgcm.pDirectDraw, NULL, DDSCL_NORMAL);
704 if (hr != DD_OK)
705 {
706 crWarning("Failed to SetCooperativeLevel (%x)\n", hr);
707 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
708 g_crvboxhgcm.pDirectDraw = NULL;
709 }
710 crDebug("Created DirectDraw and set CooperativeLevel successfully\n");
711 }
712 }
713
714 /* Try to allocate buffer via DDRAW */
715 if (g_crvboxhgcm.pDirectDraw)
716 {
717 DDSURFACEDESC ddsd;
718 HRESULT hr;
719 LPDIRECTDRAWSURFACE lpDDS;
720
721 memset(&ddsd, 0, sizeof(ddsd));
722 ddsd.dwSize = sizeof(ddsd);
723
724 /* @todo DDSCAPS_VIDEOMEMORY ain't working for some reason
725 * also, it would be better to request dwLinearSize but it fails too
726 * ddsd.dwLinearSize = sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size;
727 */
728
729 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
730 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
731 /* use 1 byte per pixel format */
732 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
733 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
734 ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
735 ddsd.ddpfPixelFormat.dwRBitMask = 0xFF;
736 ddsd.ddpfPixelFormat.dwGBitMask = 0;
737 ddsd.ddpfPixelFormat.dwBBitMask = 0;
738 /* request given buffer size, rounded to 1k */
739 ddsd.dwWidth = 1024;
740 ddsd.dwHeight = (sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size + ddsd.dwWidth-1)/ddsd.dwWidth;
741
742 hr = IDirectDraw_CreateSurface(g_crvboxhgcm.pDirectDraw, &ddsd, &lpDDS, NULL);
743 if (hr != DD_OK)
744 {
745 crWarning("Failed to create DirectDraw surface (%x)\n", hr);
746 }
747 else
748 {
749 crDebug("Created DirectDraw surface (%x)\n", lpDDS);
750
751 hr = IDirectDrawSurface_Lock(lpDDS, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL);
752 if (hr != DD_OK)
753 {
754 crWarning("Failed to lock DirectDraw surface (%x)\n", hr);
755 IDirectDrawSurface_Release(lpDDS);
756 }
757 else
758 {
759 uint32_t cbLocked;
760 cbLocked = (ddsd.dwFlags & DDSD_LINEARSIZE) ? ddsd.dwLinearSize : ddsd.lPitch*ddsd.dwHeight;
761
762 crDebug("Locked %d bytes DirectDraw surface\n", cbLocked);
763
764 buf = (CRVBOXHGCMBUFFER *) ddsd.lpSurface;
765 CRASSERT(buf);
766 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
767 buf->kind = CR_VBOXHGCM_DDRAW_SURFACE;
768 buf->allocated = cbLocked;
769 buf->pDDS = lpDDS;
770 }
771 }
772 }
773#endif
774
775 /* We're either on host side, or we failed to allocate DDRAW buffer */
776 if (!buf)
777 {
778 crDebug("Using system malloc\n");
779 buf = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size );
780 CRASSERT(buf);
781 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
782 buf->kind = CR_VBOXHGCM_MEMORY;
783 buf->allocated = conn->buffer_size;
784#ifdef RT_OS_WINDOWS
785 buf->pDDS = NULL;
786#endif
787 }
788 }
789
790#ifdef CHROMIUM_THREADSAFE
791 crUnlockMutex(&g_crvboxhgcm.mutex);
792#endif
793
794 return (void *)( buf + 1 );
795
796}
797
798static void *crVBoxHGCMAlloc(CRConnection *conn)
799{
800 void *pvBuff;
801 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
802 pvBuff = _crVBoxHGCMAlloc(conn);
803 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
804 return pvBuff;
805}
806
807static void _crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
808{
809 int rc;
810 int32_t callRes;
811
812#ifdef IN_GUEST
813 if (conn->u32InjectClientID)
814 {
815 CRVBOXHGCMINJECT parms;
816
817 parms.hdr.result = VERR_WRONG_ORDER;
818 parms.hdr.u32ClientID = conn->u32ClientID;
819 parms.hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
820 parms.hdr.cParms = SHCRGL_CPARMS_INJECT;
821
822 parms.u32ClientID.type = VMMDevHGCMParmType_32bit;
823 parms.u32ClientID.u.value32 = conn->u32InjectClientID;
824
825 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
826 parms.pBuffer.u.Pointer.size = len;
827 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
828
829 rc = crVBoxHGCMCall(&parms, sizeof(parms));
830 callRes = parms.hdr.result;
831 }
832 else
833#endif
834 {
835 CRVBOXHGCMWRITE parms;
836
837 parms.hdr.result = VERR_WRONG_ORDER;
838 parms.hdr.u32ClientID = conn->u32ClientID;
839 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
840 parms.hdr.cParms = SHCRGL_CPARMS_WRITE;
841
842 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
843 parms.pBuffer.u.Pointer.size = len;
844 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
845
846 rc = crVBoxHGCMCall(&parms, sizeof(parms));
847 callRes = parms.hdr.result;
848 }
849
850 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
851 {
852 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
853 }
854}
855
856static void crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
857{
858 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
859 _crVBoxHGCMWriteExact(conn, buf, len);
860 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
861}
862
863static void crVBoxHGCMReadExact( CRConnection *conn, const void *buf, unsigned int len )
864{
865 CRVBOXHGCMREAD parms;
866 int rc;
867
868 parms.hdr.result = VERR_WRONG_ORDER;
869 parms.hdr.u32ClientID = conn->u32ClientID;
870 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
871 parms.hdr.cParms = SHCRGL_CPARMS_READ;
872
873 CRASSERT(!conn->pBuffer); //make sure there's no data to process
874 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
875 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
876 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
877
878 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
879 parms.cbBuffer.u.value32 = 0;
880
881 rc = crVBoxHGCMCall(&parms, sizeof(parms));
882
883 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
884 {
885 crWarning("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
886 return;
887 }
888
889 if (parms.cbBuffer.u.value32)
890 {
891 //conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
892 conn->pBuffer = conn->pHostBuffer;
893 conn->cbBuffer = parms.cbBuffer.u.value32;
894 }
895
896 if (conn->cbBuffer)
897 _crVBoxHGCMReceiveMessage(conn);
898
899}
900
901/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
902 * This halves the number of HGCM calls we do,
903 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
904 */
905static void
906crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, CRVBOXHGCMBUFFERKIND bufferKind)
907{
908 CRVBOXHGCMWRITEREAD parms;
909 int rc;
910
911 parms.hdr.result = VERR_WRONG_ORDER;
912 parms.hdr.u32ClientID = conn->u32ClientID;
913 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
914 parms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ;
915
916 //if (bufferKind != CR_VBOXHGCM_DDRAW_SURFACE)
917 {
918 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
919 parms.pBuffer.u.Pointer.size = len;
920 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
921 }
922 /*else ///@todo it fails badly, have to check why. bird: This fails because buf isn't a physical address?
923 {
924 parms.pBuffer.type = VMMDevHGCMParmType_PhysAddr;
925 parms.pBuffer.u.Pointer.size = len;
926 parms.pBuffer.u.Pointer.u.physAddr = (uintptr_t) buf;
927 }*/
928
929 CRASSERT(!conn->pBuffer); //make sure there's no data to process
930 parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out;
931 parms.pWriteback.u.Pointer.size = conn->cbHostBufferAllocated;
932 parms.pWriteback.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
933
934 parms.cbWriteback.type = VMMDevHGCMParmType_32bit;
935 parms.cbWriteback.u.value32 = 0;
936
937 rc = crVBoxHGCMCall(&parms, sizeof(parms));
938
939 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
940 {
941
942 if ((VERR_BUFFER_OVERFLOW == parms.hdr.result) && RT_SUCCESS(rc))
943 {
944 /* reallocate buffer and retry */
945
946 CRASSERT(parms.cbWriteback.u.value32>conn->cbHostBufferAllocated);
947
948 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, parms.cbWriteback.u.value32);
949
950 crFree(conn->pHostBuffer);
951 conn->cbHostBufferAllocated = parms.cbWriteback.u.value32;
952 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
953
954 crVBoxHGCMReadExact(conn, buf, len);
955
956 return;
957 }
958 else
959 {
960 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x %x\n", len, rc, parms.hdr.result);
961 return;
962 }
963 }
964
965 if (parms.cbWriteback.u.value32)
966 {
967 //conn->pBuffer = (uint8_t*) parms.pWriteback.u.Pointer.u.linearAddr;
968 conn->pBuffer = conn->pHostBuffer;
969 conn->cbBuffer = parms.cbWriteback.u.value32;
970 }
971
972 if (conn->cbBuffer)
973 _crVBoxHGCMReceiveMessage(conn);
974}
975
976static void crVBoxHGCMSend(CRConnection *conn, void **bufp,
977 const void *start, unsigned int len)
978{
979 CRVBOXHGCMBUFFER *hgcm_buffer;
980 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
981
982 if (!bufp) /* We're sending a user-allocated buffer. */
983 {
984#ifndef IN_GUEST
985 //@todo remove temp buffer allocation in unpacker
986 /* we're at the host side, so just store data until guest polls us */
987 _crVBoxHGCMWriteBytes(conn, start, len);
988#else
989 CRASSERT(!conn->u32InjectClientID);
990 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
991 crVBoxHGCMWriteReadExact(conn, start, len, CR_VBOXHGCM_USERALLOCATED);
992#endif
993 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
994 return;
995 }
996
997 /* The region [start .. start + len + 1] lies within a buffer that
998 * was allocated with crVBoxHGCMAlloc() and can be put into the free
999 * buffer pool when we're done sending it.
1000 */
1001
1002 hgcm_buffer = (CRVBOXHGCMBUFFER *)(*bufp) - 1;
1003 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1004
1005 /* Length would be passed as part of HGCM pointer description
1006 * No need to prepend it to the buffer
1007 */
1008#ifdef IN_GUEST
1009 if (conn->u32InjectClientID)
1010 {
1011 _crVBoxHGCMWriteExact(conn, start, len);
1012 }
1013 else
1014#endif
1015 crVBoxHGCMWriteReadExact(conn, start, len, hgcm_buffer->kind);
1016
1017 /* Reclaim this pointer for reuse */
1018#ifdef CHROMIUM_THREADSAFE
1019 crLockMutex(&g_crvboxhgcm.mutex);
1020#endif
1021 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
1022#ifdef CHROMIUM_THREADSAFE
1023 crUnlockMutex(&g_crvboxhgcm.mutex);
1024#endif
1025
1026 /* Since the buffer's now in the 'free' buffer pool, the caller can't
1027 * use it any more. Setting bufp to NULL will make sure the caller
1028 * doesn't try to re-use the buffer.
1029 */
1030 *bufp = NULL;
1031
1032 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1033}
1034
1035static void crVBoxHGCMPollHost(CRConnection *conn)
1036{
1037 CRVBOXHGCMREAD parms;
1038 int rc;
1039
1040 CRASSERT(!conn->pBuffer);
1041
1042 parms.hdr.result = VERR_WRONG_ORDER;
1043 parms.hdr.u32ClientID = conn->u32ClientID;
1044 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
1045 parms.hdr.cParms = SHCRGL_CPARMS_READ;
1046
1047 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
1048 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
1049 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
1050
1051 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
1052 parms.cbBuffer.u.value32 = 0;
1053
1054 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1055
1056 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1057 {
1058 crDebug("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
1059 return;
1060 }
1061
1062 if (parms.cbBuffer.u.value32)
1063 {
1064 conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
1065 conn->cbBuffer = parms.cbBuffer.u.value32;
1066 }
1067}
1068
1069static void crVBoxHGCMSingleRecv(CRConnection *conn, void *buf, unsigned int len)
1070{
1071 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1072 crVBoxHGCMReadExact(conn, buf, len);
1073 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1074}
1075
1076static void _crVBoxHGCMFree(CRConnection *conn, void *buf)
1077{
1078 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1079
1080 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1081
1082 /*@todo wrong len for redir buffers*/
1083 conn->recv_credits += hgcm_buffer->len;
1084
1085 switch (hgcm_buffer->kind)
1086 {
1087 case CR_VBOXHGCM_MEMORY:
1088#ifdef RT_OS_WINDOWS
1089 case CR_VBOXHGCM_DDRAW_SURFACE:
1090#endif
1091#ifdef CHROMIUM_THREADSAFE
1092 crLockMutex(&g_crvboxhgcm.mutex);
1093#endif
1094 if (g_crvboxhgcm.bufpool) {
1095 //@todo o'rly?
1096 /* pool may have been deallocated just a bit earlier in response
1097 * to a SIGPIPE (Broken Pipe) signal.
1098 */
1099 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
1100 }
1101#ifdef CHROMIUM_THREADSAFE
1102 crUnlockMutex(&g_crvboxhgcm.mutex);
1103#endif
1104 break;
1105
1106 case CR_VBOXHGCM_MEMORY_BIG:
1107 crFree( hgcm_buffer );
1108 break;
1109
1110 default:
1111 crError( "Weird buffer kind trying to free in crVBoxHGCMFree: %d", hgcm_buffer->kind );
1112 }
1113}
1114
1115static void crVBoxHGCMFree(CRConnection *conn, void *buf)
1116{
1117 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1118 _crVBoxHGCMFree(conn, buf);
1119 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1120}
1121
1122static void _crVBoxHGCMReceiveMessage(CRConnection *conn)
1123{
1124 uint32_t len;
1125 CRVBOXHGCMBUFFER *hgcm_buffer;
1126 CRMessage *msg;
1127 CRMessageType cached_type;
1128
1129 len = conn->cbBuffer;
1130 CRASSERT(len > 0);
1131 CRASSERT(conn->pBuffer);
1132
1133#ifndef IN_GUEST
1134 if (conn->allow_redir_ptr)
1135 {
1136#endif //IN_GUEST
1137 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
1138
1139 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1140 hgcm_buffer->len = sizeof(CRMessageRedirPtr);
1141
1142 msg = (CRMessage *) (hgcm_buffer + 1);
1143
1144 msg->header.type = CR_MESSAGE_REDIR_PTR;
1145 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
1146 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
1147
1148 cached_type = msg->redirptr.pMessage->type;
1149
1150 conn->cbBuffer = 0;
1151 conn->pBuffer = NULL;
1152#ifndef IN_GUEST
1153 }
1154 else
1155 {
1156 if ( len <= conn->buffer_size )
1157 {
1158 /* put in pre-allocated buffer */
1159 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1160 }
1161 else
1162 {
1163 /* allocate new buffer,
1164 * not using pool here as it's most likely one time transfer of huge texture
1165 */
1166 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
1167 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1168 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
1169 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
1170# ifdef RT_OS_WINDOWS
1171 hgcm_buffer->pDDS = NULL;
1172# endif
1173 }
1174
1175 hgcm_buffer->len = len;
1176 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
1177
1178 msg = (CRMessage *) (hgcm_buffer + 1);
1179 cached_type = msg->header.type;
1180 }
1181#endif //IN_GUEST
1182
1183 conn->recv_credits -= len;
1184 conn->total_bytes_recv += len;
1185 conn->recv_count++;
1186
1187 crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
1188
1189 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
1190 * OOB messages are the programmer's problem. -- Humper 12/17/01
1191 */
1192 if (cached_type != CR_MESSAGE_OPCODES
1193 && cached_type != CR_MESSAGE_OOB
1194 && cached_type != CR_MESSAGE_GATHER)
1195 {
1196 _crVBoxHGCMFree(conn, msg);
1197 }
1198}
1199
1200static void crVBoxHGCMReceiveMessage(CRConnection *conn)
1201{
1202 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1203 _crVBoxHGCMReceiveMessage(conn);
1204 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1205}
1206
1207
1208/*
1209 * Called on host side only, to "accept" client connection
1210 */
1211static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
1212{
1213 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1214 CRASSERT(conn && conn->pHostBuffer);
1215#ifdef IN_GUEST
1216 CRASSERT(FALSE);
1217#endif
1218 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1219}
1220
1221static int crVBoxHGCMSetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
1222{
1223 CRVBOXHGCMSETVERSION parms;
1224 int rc;
1225
1226 parms.hdr.result = VERR_WRONG_ORDER;
1227 parms.hdr.u32ClientID = conn->u32ClientID;
1228 parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_VERSION;
1229 parms.hdr.cParms = SHCRGL_CPARMS_SET_VERSION;
1230
1231 parms.vMajor.type = VMMDevHGCMParmType_32bit;
1232 parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
1233 parms.vMinor.type = VMMDevHGCMParmType_32bit;
1234 parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
1235
1236 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1237
1238 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1239 {
1240 Assert(0);
1241
1242 crWarning("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
1243 parms.vMajor.u.value32, parms.vMinor.u.value32);
1244 return FALSE;
1245 }
1246
1247 conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
1248 conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
1249
1250 return TRUE;
1251}
1252
1253static int crVBoxHGCMSetPID(CRConnection *conn, CRpid pid)
1254{
1255 CRVBOXHGCMSETPID parms;
1256 int rc;
1257
1258 parms.hdr.result = VERR_WRONG_ORDER;
1259 parms.hdr.u32ClientID = conn->u32ClientID;
1260 parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_PID;
1261 parms.hdr.cParms = SHCRGL_CPARMS_SET_PID;
1262
1263 parms.u64PID.type = VMMDevHGCMParmType_64bit;
1264 parms.u64PID.u.value64 = (uintptr_t) pid;
1265
1266 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1267
1268 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1269 {
1270 Assert(0);
1271
1272 crWarning("SHCRGL_GUEST_FN_SET_PID failed!");
1273 return FALSE;
1274 }
1275
1276 return TRUE;
1277}
1278
1279/**
1280 * The function that actually connects. This should only be called by clients,
1281 * guests in vbox case.
1282 * Servers go through crVBoxHGCMAccept;
1283 */
1284/*@todo use vbglR3Something here */
1285static int crVBoxHGCMDoConnect( CRConnection *conn )
1286{
1287#ifdef IN_GUEST
1288 VBoxGuestHGCMConnectInfo info;
1289
1290#ifdef RT_OS_WINDOWS
1291 DWORD cbReturned;
1292
1293 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1294
1295 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
1296 {
1297 /* open VBox guest driver */
1298 g_crvboxhgcm.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
1299 GENERIC_READ | GENERIC_WRITE,
1300 FILE_SHARE_READ | FILE_SHARE_WRITE,
1301 NULL,
1302 OPEN_EXISTING,
1303 FILE_ATTRIBUTE_NORMAL,
1304 NULL);
1305
1306 /* @todo check if we could rollback to softwareopengl */
1307 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
1308 {
1309 Assert(0);
1310 crDebug("could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
1311 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1312 return FALSE;
1313 }
1314 }
1315#else
1316 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1317 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
1318 {
1319 g_crvboxhgcm.iGuestDrv = open(VBOXGUEST_USER_DEVICE_NAME, O_RDWR, 0);
1320 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
1321 {
1322 crDebug("could not open Guest Additions kernel module! rc = %d\n", errno);
1323 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1324 Assert(0);
1325 return FALSE;
1326 }
1327 }
1328#endif
1329
1330 memset (&info, 0, sizeof (info));
1331 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
1332 strcpy (info.Loc.u.host.achName, "VBoxSharedCrOpenGL");
1333
1334#ifdef RT_OS_WINDOWS
1335 if (DeviceIoControl(g_crvboxhgcm.hGuestDrv,
1336 VBOXGUEST_IOCTL_HGCM_CONNECT,
1337 &info, sizeof (info),
1338 &info, sizeof (info),
1339 &cbReturned,
1340 NULL))
1341#elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1342 VBGLBIGREQ Hdr;
1343 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
1344 Hdr.cbData = sizeof(info);
1345 Hdr.pvDataR3 = &info;
1346# if HC_ARCH_BITS == 32
1347 Hdr.u32Padding = 0;
1348# endif
1349 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &Hdr) >= 0)
1350#else
1351 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info)) >= 0)
1352#endif
1353 {
1354 if (info.result == VINF_SUCCESS)
1355 {
1356 int rc;
1357 conn->u32ClientID = info.u32ClientID;
1358 crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
1359
1360 rc = crVBoxHGCMSetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
1361 if (!rc)
1362 {
1363 return rc;
1364 }
1365 rc = crVBoxHGCMSetPID(conn, crGetPID());
1366 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1367 return rc;
1368 }
1369 else
1370 {
1371 crDebug("HGCM connect failed with rc=0x%x\n", info.result);
1372 Assert(0);
1373
1374 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1375 return FALSE;
1376 }
1377 }
1378 else
1379 {
1380#ifdef RT_OS_WINDOWS
1381 DWORD winEr = GetLastError();
1382 Assert(0);
1383 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", winEr);
1384#else
1385 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", errno);
1386#endif
1387 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1388 return FALSE;
1389 }
1390
1391 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1392 return TRUE;
1393
1394#else /*#ifdef IN_GUEST*/
1395 crError("crVBoxHGCMDoConnect called on host side!");
1396 CRASSERT(FALSE);
1397 return FALSE;
1398#endif
1399}
1400
1401/*@todo same, replace DeviceIoControl with vbglR3DoIOCtl */
1402static void crVBoxHGCMDoDisconnect( CRConnection *conn )
1403{
1404#ifdef IN_GUEST
1405 VBoxGuestHGCMDisconnectInfo info;
1406# ifdef RT_OS_WINDOWS
1407 DWORD cbReturned;
1408# endif
1409 int i;
1410#endif
1411
1412 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1413
1414 if (conn->pHostBuffer)
1415 {
1416 crFree(conn->pHostBuffer);
1417 conn->pHostBuffer = NULL;
1418 conn->cbHostBuffer = 0;
1419 conn->cbHostBufferAllocated = 0;
1420 }
1421
1422 conn->pBuffer = NULL;
1423 conn->cbBuffer = 0;
1424
1425 //@todo hold lock here?
1426 if (conn->type == CR_VBOXHGCM)
1427 {
1428 --g_crvboxhgcm.num_conns;
1429
1430 if (conn->index < g_crvboxhgcm.num_conns)
1431 {
1432 g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
1433 g_crvboxhgcm.conns[conn->index]->index = conn->index;
1434 }
1435 else g_crvboxhgcm.conns[conn->index] = NULL;
1436
1437 conn->type = CR_NO_CONNECTION;
1438 }
1439
1440#ifndef IN_GUEST
1441#else /* IN_GUEST */
1442 if (conn->u32ClientID)
1443 {
1444 memset (&info, 0, sizeof (info));
1445 info.u32ClientID = conn->u32ClientID;
1446
1447# ifdef RT_OS_WINDOWS
1448 if ( !DeviceIoControl(g_crvboxhgcm.hGuestDrv,
1449 VBOXGUEST_IOCTL_HGCM_DISCONNECT,
1450 &info, sizeof (info),
1451 &info, sizeof (info),
1452 &cbReturned,
1453 NULL) )
1454 {
1455 crDebug("Disconnect failed with %x\n", GetLastError());
1456 }
1457# elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1458 VBGLBIGREQ Hdr;
1459 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
1460 Hdr.cbData = sizeof(info);
1461 Hdr.pvDataR3 = &info;
1462# if HC_ARCH_BITS == 32
1463 Hdr.u32Padding = 0;
1464# endif
1465 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Hdr) >= 0)
1466# else
1467 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info, sizeof (info)) < 0)
1468 {
1469 crDebug("Disconnect failed with %x\n", errno);
1470 }
1471# endif
1472
1473 conn->u32ClientID = 0;
1474 }
1475
1476 /* see if any connections remain */
1477 for (i = 0; i < g_crvboxhgcm.num_conns; i++)
1478 if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
1479 break;
1480
1481 /* close guest additions driver*/
1482 if (i>=g_crvboxhgcm.num_conns)
1483 {
1484# ifdef RT_OS_WINDOWS
1485 CloseHandle(g_crvboxhgcm.hGuestDrv);
1486 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
1487# else
1488 close(g_crvboxhgcm.iGuestDrv);
1489 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
1490# endif
1491 }
1492#endif /* IN_GUEST */
1493
1494 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1495}
1496
1497static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
1498{
1499 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1500 _crVBoxHGCMFree(conn, mess);
1501 CRASSERT(FALSE);
1502 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1503}
1504
1505static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1506{
1507 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1508 CRASSERT(FALSE);
1509 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1510}
1511
1512#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1513
1514bool _crVBoxHGSMIInit()
1515{
1516#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1517 static
1518#endif
1519 int bHasHGSMI = -1;
1520
1521 if (bHasHGSMI < 0)
1522 {
1523 int rc;
1524#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1525 rc = VBoxCrHgsmiInit();
1526#else
1527 VBOXCRHGSMI_CALLBACKS Callbacks;
1528 Callbacks.pfnClientCreate = _crVBoxHGSMIClientCreate;
1529 Callbacks.pfnClientDestroy = _crVBoxHGSMIClientDestroy;
1530 rc = VBoxCrHgsmiInit(&Callbacks);
1531#endif
1532 AssertRC(rc);
1533 if (RT_SUCCESS(rc))
1534 bHasHGSMI = 1;
1535 else
1536 bHasHGSMI = 0;
1537 }
1538
1539 Assert(bHasHGSMI);
1540
1541 return bHasHGSMI;
1542}
1543
1544void _crVBoxHGSMITearDown()
1545{
1546 VBoxCrHgsmiTerm();
1547}
1548
1549static void *_crVBoxHGSMIDoAlloc(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1550{
1551 PVBOXUHGSMI_BUFFER buf;
1552 CRVBOXHGCMBUFFER *pData = NULL;
1553 uint32_t cbSize = conn->buffer_size;
1554 int rc;
1555
1556 buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
1557 Assert(buf);
1558 if (buf)
1559 {
1560 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1561 buf->pvUserData = pClient;
1562 fFlags.Value = 0;
1563 fFlags.bDiscard = 1;
1564 rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
1565 if (RT_SUCCESS(rc))
1566 {
1567 pData->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1568 pData->kind = CR_VBOXHGCM_UHGSMI_BUFFER;
1569 pData->pBuffer = buf;
1570 }
1571 else
1572 {
1573 crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
1574 }
1575 return CRVBOXHGSMI_BUF_DATA(pData);
1576 }
1577
1578 /* fall back */
1579 return _crVBoxHGCMAlloc(conn);
1580}
1581
1582static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
1583{
1584 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1585
1586 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1587
1588 if (hgcm_buffer->kind == CR_VBOXHGCM_UHGSMI_BUFFER)
1589 {
1590 PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1591 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1592 pBuf->pfnUnlock(pBuf);
1593 _crVBoxHGSMIBufFree(pClient, pBuf);
1594 }
1595 else
1596 {
1597 _crVBoxHGCMFree(conn, buf);
1598 }
1599}
1600
1601static void *crVBoxHGSMIAlloc(CRConnection *conn)
1602{
1603 PCRVBOXHGSMI_CLIENT pClient;
1604 void *pvBuf;
1605
1606 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1607
1608 pClient = _crVBoxHGSMIClientGet(conn);
1609 if (pClient)
1610 {
1611 pvBuf = _crVBoxHGSMIDoAlloc(conn, pClient);
1612 Assert(pvBuf);
1613 }
1614 else
1615 {
1616 pvBuf = _crVBoxHGCMAlloc(conn);
1617 }
1618
1619 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1620
1621 return pvBuf;
1622}
1623
1624static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
1625{
1626 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1627 _crVBoxHGSMIFree(conn, buf);
1628 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1629}
1630
1631static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1632{
1633 CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1634 int rc;
1635 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1636 PVBOXUHGSMI_BUFFER pRecvBuffer;
1637 uint32_t cbBuffer;
1638
1639 Assert(parms);
1640
1641 parms->hdr.result = VERR_WRONG_ORDER;
1642 parms->hdr.u32ClientID = conn->u32ClientID;
1643 parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
1644// parms->hdr.u32Reserved = 0;
1645
1646 CRASSERT(!conn->pBuffer); //make sure there's no data to process
1647 parms->iBuffer = 1;
1648 parms->cbBuffer = 0;
1649
1650 _crVBoxHGSMICmdBufferUnlock(pClient);
1651
1652 pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1653 Assert(pRecvBuffer);
1654 if (!pRecvBuffer)
1655 return;
1656
1657 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1658
1659 aSubmit[1].pBuf = pRecvBuffer;
1660 aSubmit[1].offData = 0;
1661 aSubmit[1].cbData = pRecvBuffer->cbBuffer;
1662 aSubmit[1].fFlags.Value = 0;
1663 aSubmit[1].fFlags.bHostWriteOnly = 1;
1664
1665 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
1666 AssertRC(rc);
1667 if (RT_FAILURE(rc))
1668 {
1669 crError("pfnBufferSubmitAsynch failed with %d \n", rc);
1670 return;
1671 }
1672
1673 _crVBoxHGSMIWaitCmd(pClient);
1674
1675 parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1676 Assert(parms);
1677 if (!parms)
1678 {
1679 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1680 return;
1681 }
1682
1683 if (RT_SUCCESS(parms->hdr.result))
1684 cbBuffer = parms->cbBuffer;
1685 else
1686 cbBuffer = 0;
1687
1688 _crVBoxHGSMICmdBufferUnlock(pClient);
1689
1690 if (cbBuffer)
1691 {
1692 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
1693 Assert(pvData);
1694 if (pvData)
1695 {
1696 conn->pBuffer = pvData;
1697 conn->cbBuffer = cbBuffer;
1698 }
1699 }
1700}
1701
1702static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1703{
1704 _crVBoxHGSMIPollHost(conn, pClient);
1705
1706 if (conn->cbBuffer)
1707 _crVBoxHGCMReceiveMessage(conn);
1708}
1709
1710/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
1711 * This halves the number of HGCM calls we do,
1712 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
1713 */
1714static void
1715_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
1716{
1717 CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1718 int rc;
1719 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
1720 PVBOXUHGSMI_BUFFER pBuf = NULL;
1721 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1722// uint32_t cbBuffer;
1723
1724 parms->hdr.result = VERR_WRONG_ORDER;
1725 parms->hdr.u32ClientID = conn->u32ClientID;
1726 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
1727// parms->hdr.u32Reserved = 0;
1728
1729 parms->iBuffer = 1;
1730
1731 CRASSERT(!conn->pBuffer); //make sure there's no data to process
1732 parms->iWriteback = 2;
1733 parms->cbWriteback = 0;
1734
1735 _crVBoxHGSMICmdBufferUnlock(pClient);
1736
1737 if (!bIsBuffer)
1738 {
1739 void *pvBuf;
1740 pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
1741 Assert(pBuf);
1742 if (!pBuf)
1743 {
1744 /* fallback */
1745 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1746 return;
1747 }
1748
1749 Assert(!offBuffer);
1750
1751 offBuffer = 0;
1752 fFlags.Value = 0;
1753 fFlags.bDiscard = 1;
1754 fFlags.bWriteOnly = 1;
1755 rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
1756 AssertRC(rc);
1757 if (RT_SUCCESS(rc))
1758 {
1759 memcpy(pvBuf, buf, len);
1760 rc = pBuf->pfnUnlock(pBuf);
1761 AssertRC(rc);
1762 CRASSERT(RT_SUCCESS(rc));
1763 }
1764 else
1765 {
1766 _crVBoxHGSMIBufFree(pClient, pBuf);
1767 /* fallback */
1768 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1769 return;
1770 }
1771 }
1772 else
1773 {
1774 pBuf = (PVBOXUHGSMI_BUFFER)buf;
1775 }
1776
1777 do
1778 {
1779 PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1780 Assert(pRecvBuffer);
1781 if (!pRecvBuffer)
1782 {
1783 break;
1784 }
1785
1786 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1787
1788 aSubmit[1].pBuf = pBuf;
1789 aSubmit[1].offData = offBuffer;
1790 aSubmit[1].cbData = len;
1791 aSubmit[1].fFlags.Value = 0;
1792 aSubmit[1].fFlags.bHostReadOnly = 1;
1793
1794 aSubmit[2].pBuf = pRecvBuffer;
1795 aSubmit[2].offData = 0;
1796 aSubmit[2].cbData = pRecvBuffer->cbBuffer;
1797 aSubmit[2].fFlags.Value = 0;
1798
1799 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 3);
1800 AssertRC(rc);
1801 if (RT_FAILURE(rc))
1802 {
1803 crError("pfnBufferSubmitAsynch failed with %d \n", rc);
1804 break;
1805 }
1806
1807 _crVBoxHGSMIWaitCmd(pClient);
1808
1809 parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1810 Assert(parms);
1811 if (parms)
1812 {
1813 uint32_t cbWriteback = parms->cbWriteback;
1814 rc = parms->hdr.result;
1815 _crVBoxHGSMICmdBufferUnlock(pClient);
1816#ifdef DEBUG
1817 parms = NULL;
1818#endif
1819 if (RT_SUCCESS(rc))
1820 {
1821 if (cbWriteback)
1822 {
1823 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
1824 Assert(pvData);
1825 if (pvData)
1826 {
1827 conn->pBuffer = pvData;
1828 conn->cbBuffer = cbWriteback;
1829 _crVBoxHGCMReceiveMessage(conn);
1830 }
1831 }
1832 }
1833 else if (VERR_BUFFER_OVERFLOW == rc)
1834 {
1835 PVBOXUHGSMI_BUFFER pOldBuf = pClient->pHGBuffer;
1836 Assert(!pClient->pvHGBuffer);
1837 CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
1838 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
1839
1840 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback),
1841 VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL, &pClient->pHGBuffer);
1842 AssertRC(rc);
1843 CRASSERT(RT_SUCCESS(rc));
1844 if (RT_SUCCESS(rc))
1845 {
1846 rc = pOldBuf->pfnDestroy(pOldBuf);
1847 CRASSERT(RT_SUCCESS(rc));
1848
1849 _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
1850 }
1851 else
1852 {
1853 crFree(conn->pHostBuffer);
1854 conn->cbHostBufferAllocated = cbWriteback;
1855 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
1856 crVBoxHGCMReadExact(conn, NULL, cbWriteback);
1857 }
1858 }
1859 else
1860 {
1861 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
1862 }
1863 }
1864 else
1865 {
1866 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1867 break;
1868 }
1869 } while (0);
1870
1871 if (!bIsBuffer)
1872 _crVBoxHGSMIBufFree(pClient, pBuf);
1873
1874 return;
1875}
1876
1877static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
1878{
1879 int rc;
1880 int32_t callRes;
1881 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1882
1883#ifdef IN_GUEST
1884 if (conn->u32InjectClientID)
1885 {
1886 CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1887 Assert(parms);
1888 if (!parms)
1889 {
1890 return;
1891 }
1892
1893 parms->hdr.result = VERR_WRONG_ORDER;
1894 parms->hdr.u32ClientID = conn->u32ClientID;
1895 parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
1896// parms->hdr.u32Reserved = 0;
1897
1898 parms->u32ClientID = conn->u32InjectClientID;
1899
1900 parms->iBuffer = 1;
1901 _crVBoxHGSMICmdBufferUnlock(pClient);
1902
1903 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1904
1905 aSubmit[1].pBuf = pBuf;
1906 aSubmit[1].offData = offStart;
1907 aSubmit[1].cbData = len;
1908 aSubmit[1].fFlags.Value = 0;
1909 aSubmit[1].fFlags.bHostReadOnly = 1;
1910
1911 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
1912 AssertRC(rc);
1913 if (RT_SUCCESS(rc))
1914 {
1915 _crVBoxHGSMIWaitCmd(pClient);
1916 /* @todo: do we need to wait for completion actually?
1917 * NOTE: in case we do not need completion,
1918 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
1919// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
1920
1921 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1922 }
1923 else
1924 {
1925 /* we can not recover at this point, report error & exit */
1926 crError("pfnBufferSubmitAsynch failed with %d \n", rc);
1927 }
1928 }
1929 else
1930#endif
1931 {
1932 CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
1933
1934 parms->hdr.result = VERR_WRONG_ORDER;
1935 parms->hdr.u32ClientID = conn->u32ClientID;
1936 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
1937// parms->hdr.u32Reserved = 0;
1938
1939 parms->iBuffer = 1;
1940 _crVBoxHGSMICmdBufferUnlock(pClient);
1941
1942 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1943
1944 aSubmit[1].pBuf = pBuf;
1945 aSubmit[1].offData = offStart;
1946 aSubmit[1].cbData = len;
1947 aSubmit[1].fFlags.Value = 0;
1948 aSubmit[1].fFlags.bHostReadOnly = 1;
1949
1950 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
1951 AssertRC(rc);
1952 if (RT_SUCCESS(rc))
1953 {
1954 _crVBoxHGSMIWaitCmd(pClient);
1955 /* @todo: do we need to wait for completion actually?
1956 * NOTE: in case we do not need completion,
1957 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
1958// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
1959
1960 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1961 }
1962 else
1963 {
1964 /* we can not recover at this point, report error & exit */
1965 crError("Failed to submit CrHhgsmi buffer");
1966 }
1967 }
1968
1969 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
1970 {
1971 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
1972 }
1973}
1974
1975static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
1976 const void *start, unsigned int len)
1977{
1978 PCRVBOXHGSMI_CLIENT pClient;
1979 PVBOXUHGSMI_BUFFER pBuf;
1980 CRVBOXHGCMBUFFER *hgcm_buffer;
1981
1982 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1983
1984 if (!bufp) /* We're sending a user-allocated buffer. */
1985 {
1986 pClient = _crVBoxHGSMIClientGet(conn);
1987 if (pClient)
1988 {
1989#ifndef IN_GUEST
1990 //@todo remove temp buffer allocation in unpacker
1991 /* we're at the host side, so just store data until guest polls us */
1992 _crVBoxHGCMWriteBytes(conn, start, len);
1993#else
1994 CRASSERT(!conn->u32InjectClientID);
1995 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
1996 _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
1997#endif
1998 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1999 return;
2000 }
2001
2002 /* fallback */
2003 crVBoxHGCMSend(conn, bufp, start, len);
2004 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2005 return;
2006 }
2007
2008 hgcm_buffer = (CRVBOXHGCMBUFFER *) *bufp - 1;
2009 Assert(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2010 if (hgcm_buffer->kind != CR_VBOXHGCM_UHGSMI_BUFFER)
2011 {
2012 /* fallback */
2013 crVBoxHGCMSend(conn, bufp, start, len);
2014 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2015 return;
2016 }
2017
2018 /* The region [start .. start + len + 1] lies within a buffer that
2019 * was allocated with crVBoxHGCMAlloc() and can be put into the free
2020 * buffer pool when we're done sending it.
2021 */
2022
2023 pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
2024 Assert(pBuf);
2025 if (!pBuf)
2026 {
2027 crVBoxHGCMSend(conn, bufp, start, len);
2028 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2029 return;
2030 }
2031
2032 pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
2033
2034 /* Length would be passed as part of HGCM pointer description
2035 * No need to prepend it to the buffer
2036 */
2037#ifdef IN_GUEST
2038 if (conn->u32InjectClientID)
2039 {
2040 _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
2041 }
2042 else
2043#endif
2044 {
2045 _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
2046 }
2047
2048 /* Reclaim this pointer for reuse */
2049 _crVBoxHGSMIBufFree(pClient, pBuf);
2050 /* Since the buffer's now in the 'free' buffer pool, the caller can't
2051 * use it any more. Setting bufp to NULL will make sure the caller
2052 * doesn't try to re-use the buffer.
2053 */
2054 *bufp = NULL;
2055
2056 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2057}
2058
2059static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
2060{
2061 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2062 Assert(0);
2063
2064 CRASSERT(0);
2065// PCRVBOXHGSMI_CLIENT pClient;
2066// PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
2067// if (!pBuf)
2068// return;
2069// pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
2070// _crVBoxHGSMIWriteExact(conn, pClient, pBuf, 0, len);
2071// _crVBoxHGSMIBufFree(pClient, pBuf);
2072 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2073}
2074
2075static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
2076{
2077// PCRVBOXHGSMI_CLIENT pClient;
2078// PVBOXUHGSMI_BUFFER pBuf;
2079 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2080// pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
2081// Assert(pBuf);
2082 Assert(0);
2083 CRASSERT(0);
2084// if (!pBuf)
2085// {
2086// VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2087// return;
2088// }
2089// pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
2090// _crVBoxHGSMIReadExact(conn, pClient);
2091 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2092}
2093
2094static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
2095{
2096 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2097
2098 Assert(0);
2099
2100 _crVBoxHGCMReceiveMessage(conn);
2101 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2102}
2103
2104/*
2105 * Called on host side only, to "accept" client connection
2106 */
2107static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
2108{
2109 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2110 Assert(0);
2111
2112 CRASSERT(conn && conn->pHostBuffer);
2113#ifdef IN_GUEST
2114 CRASSERT(FALSE);
2115#endif
2116 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2117}
2118
2119static int crVBoxHGSMIDoConnect( CRConnection *conn )
2120{
2121 return crVBoxHGCMDoConnect(conn);
2122}
2123
2124static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
2125{
2126#ifndef VBOX_CRHGSMI_WITH_D3DDEV
2127 if (conn->HgsmiClient.pHgsmi)
2128 {
2129 PVBOXUHGSMI pHgsmi;
2130 _crVBoxHGSMIClientTerm(&conn->HgsmiClient, &pHgsmi);
2131 Assert(pHgsmi);
2132 VBoxCrHgsmiDestroy(pHgsmi);
2133 }
2134
2135#endif
2136 crVBoxHGCMDoDisconnect(conn);
2137}
2138
2139static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
2140{
2141 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2142 Assert(0);
2143
2144 _crVBoxHGSMIFree(conn, mess);
2145 CRASSERT(FALSE);
2146
2147 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2148}
2149
2150static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
2151{
2152 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2153 Assert(0);
2154
2155 CRASSERT(FALSE);
2156 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2157}
2158#endif
2159
2160void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
2161{
2162 (void) mtu;
2163
2164 g_crvboxhgcm.recv_list = rfl;
2165 g_crvboxhgcm.close_list = cfl;
2166 if (g_crvboxhgcm.initialized)
2167 {
2168 return;
2169 }
2170
2171 VBOXCRHGSMIPROFILE_INIT();
2172
2173 g_crvboxhgcm.initialized = 1;
2174
2175#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2176 g_crvboxhgcm.bHgsmiOn = _crVBoxHGSMIInit();
2177#endif
2178
2179 g_crvboxhgcm.num_conns = 0;
2180 g_crvboxhgcm.conns = NULL;
2181
2182 /* Can't open VBox guest driver here, because it gets called for host side as well */
2183 /*@todo as we have 2 dll versions, can do it now.*/
2184
2185#ifdef RT_OS_WINDOWS
2186 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
2187 g_crvboxhgcm.pDirectDraw = NULL;
2188#else
2189 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
2190#endif
2191
2192#ifdef CHROMIUM_THREADSAFE
2193 crInitMutex(&g_crvboxhgcm.mutex);
2194 crInitMutex(&g_crvboxhgcm.recvmutex);
2195#endif
2196 g_crvboxhgcm.bufpool = crBufferPoolInit(16);
2197}
2198
2199/* Callback function used to free buffer pool entries */
2200void crVBoxHGCMBufferFree(void *data)
2201{
2202#ifdef RT_OS_WINDOWS
2203 LPDIRECTDRAWSURFACE lpDDS;
2204#endif
2205 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
2206
2207 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2208
2209 switch (hgcm_buffer->kind)
2210 {
2211 case CR_VBOXHGCM_MEMORY:
2212 crFree( hgcm_buffer );
2213 break;
2214#ifdef RT_OS_WINDOWS
2215 case CR_VBOXHGCM_DDRAW_SURFACE:
2216 lpDDS = hgcm_buffer->pDDS;
2217 CRASSERT(lpDDS);
2218 IDirectDrawSurface_Unlock(lpDDS, NULL);
2219 IDirectDrawSurface_Release(lpDDS);
2220 crDebug("DDraw surface freed (%x)\n", lpDDS);
2221 break;
2222#endif
2223 case CR_VBOXHGCM_MEMORY_BIG:
2224 crFree( hgcm_buffer );
2225 break;
2226
2227 default:
2228 crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
2229 }
2230}
2231
2232void crVBoxHGCMTearDown(void)
2233{
2234 int32_t i, cCons;
2235
2236 if (!g_crvboxhgcm.initialized) return;
2237
2238 /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
2239 * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
2240 * order of their connection.
2241 */
2242 cCons = g_crvboxhgcm.num_conns;
2243 for (i=0; i<cCons; i++)
2244 {
2245 /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
2246 crNetDisconnect(g_crvboxhgcm.conns[0]);
2247 }
2248 CRASSERT(0==g_crvboxhgcm.num_conns);
2249
2250#ifdef CHROMIUM_THREADSAFE
2251 crFreeMutex(&g_crvboxhgcm.mutex);
2252 crFreeMutex(&g_crvboxhgcm.recvmutex);
2253#endif
2254
2255 if (g_crvboxhgcm.bufpool)
2256 crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
2257 g_crvboxhgcm.bufpool = NULL;
2258
2259 g_crvboxhgcm.initialized = 0;
2260
2261 crFree(g_crvboxhgcm.conns);
2262 g_crvboxhgcm.conns = NULL;
2263
2264#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2265 if (g_crvboxhgcm.bHgsmiOn)
2266 {
2267 _crVBoxHGSMITearDown();
2268 }
2269#endif
2270
2271#ifdef RT_OS_WINDOWS
2272 if (g_crvboxhgcm.pDirectDraw)
2273 {
2274 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
2275 g_crvboxhgcm.pDirectDraw = NULL;
2276 crDebug("DirectDraw released\n");
2277 }
2278#endif
2279}
2280
2281void crVBoxHGCMConnection(CRConnection *conn)
2282{
2283 int i, found = 0;
2284 int n_bytes;
2285
2286 CRASSERT(g_crvboxhgcm.initialized);
2287
2288#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2289 if (g_crvboxhgcm.bHgsmiOn)
2290 {
2291 conn->type = CR_VBOXHGCM;
2292 conn->Alloc = crVBoxHGSMIAlloc;
2293 conn->Send = crVBoxHGSMISend;
2294 conn->SendExact = crVBoxHGSMIWriteExact;
2295 conn->Recv = crVBoxHGSMISingleRecv;
2296 conn->RecvMsg = crVBoxHGSMIReceiveMessage;
2297 conn->Free = crVBoxHGSMIFree;
2298 conn->Accept = crVBoxHGSMIAccept;
2299 conn->Connect = crVBoxHGSMIDoConnect;
2300 conn->Disconnect = crVBoxHGSMIDoDisconnect;
2301 conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
2302 conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
2303 }
2304 else
2305#endif
2306 {
2307 conn->type = CR_VBOXHGCM;
2308 conn->Alloc = crVBoxHGCMAlloc;
2309 conn->Send = crVBoxHGCMSend;
2310 conn->SendExact = crVBoxHGCMWriteExact;
2311 conn->Recv = crVBoxHGCMSingleRecv;
2312 conn->RecvMsg = crVBoxHGCMReceiveMessage;
2313 conn->Free = crVBoxHGCMFree;
2314 conn->Accept = crVBoxHGCMAccept;
2315 conn->Connect = crVBoxHGCMDoConnect;
2316 conn->Disconnect = crVBoxHGCMDoDisconnect;
2317 conn->InstantReclaim = crVBoxHGCMInstantReclaim;
2318 conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
2319 }
2320 conn->index = g_crvboxhgcm.num_conns;
2321 conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
2322 conn->actual_network = 1;
2323
2324 conn->krecv_buf_size = 0;
2325
2326 conn->pBuffer = NULL;
2327 conn->cbBuffer = 0;
2328 conn->allow_redir_ptr = 1;
2329
2330 //@todo remove this crap at all later
2331 conn->cbHostBufferAllocated = 2*1024;
2332 conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
2333 CRASSERT(conn->pHostBuffer);
2334 conn->cbHostBuffer = 0;
2335
2336 /* Find a free slot */
2337 for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
2338 if (g_crvboxhgcm.conns[i] == NULL) {
2339 conn->index = i;
2340 g_crvboxhgcm.conns[i] = conn;
2341 found = 1;
2342 break;
2343 }
2344 }
2345
2346 /* Realloc connection stack if we couldn't find a free slot */
2347 if (found == 0) {
2348 n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
2349 crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
2350 g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
2351 }
2352}
2353
2354int crVBoxHGCMRecv(void)
2355{
2356 int32_t i;
2357
2358 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2359
2360#ifdef IN_GUEST
2361 /* we're on guest side, poll host if it got something for us */
2362 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2363 {
2364 CRConnection *conn = g_crvboxhgcm.conns[i];
2365
2366 if ( !conn || conn->type == CR_NO_CONNECTION )
2367 continue;
2368
2369 if (!conn->pBuffer)
2370 {
2371#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2372 PCRVBOXHGSMI_CLIENT pClient;
2373 if (g_crvboxhgcm.bHgsmiOn && !!(pClient = _crVBoxHGSMIClientGet(conn)))
2374 {
2375 _crVBoxHGSMIPollHost(conn, pClient);
2376 }
2377 else
2378#endif
2379 {
2380 crVBoxHGCMPollHost(conn);
2381 }
2382 }
2383 }
2384#endif
2385
2386 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2387 {
2388 CRConnection *conn = g_crvboxhgcm.conns[i];
2389
2390 if ( !conn || conn->type == CR_NO_CONNECTION )
2391 continue;
2392
2393 if (conn->cbBuffer>0)
2394 {
2395 _crVBoxHGCMReceiveMessage(conn);
2396 }
2397 }
2398
2399 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2400
2401 return 0;
2402}
2403
2404CRConnection** crVBoxHGCMDump( int *num )
2405{
2406 *num = g_crvboxhgcm.num_conns;
2407
2408 return g_crvboxhgcm.conns;
2409}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette