VirtualBox

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

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

wddm: fix guest misbehave on driver update, bugfixing

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

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