VirtualBox

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

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

crOpenGL/XPDM: fix explorer crashes on windows vista/win7 guests

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