VirtualBox

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

Last change on this file since 39288 was 39288, checked in by vboxsync, 13 years ago

CrOpenGL: avoid blocked client polling & extra memcpy (block hgsmi command until completion)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 76.1 KB
Line 
1/* $Id: vboxhgcm.c 39288 2011-11-14 09:58:38Z 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 CRASSERT(pClient);
340 return pClient;
341#else
342 if (conn->HgsmiClient.pHgsmi)
343 return &conn->HgsmiClient;
344 {
345 PVBOXUHGSMI pHgsmi = VBoxCrHgsmiCreate();
346 CRASSERT(pHgsmi);
347 if (pHgsmi)
348 {
349 int rc = _crVBoxHGSMIClientInit(&conn->HgsmiClient, pHgsmi);
350 AssertRC(rc);
351 if (RT_SUCCESS(rc))
352 {
353 CRASSERT(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 CRASSERT(!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 CRASSERT(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, lerr;
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 lerr=GetLastError();
615 crDebug("vboxCall failed with %x\n", lerr);
616 /*On windows if we exceed max buffer len, we only get ERROR_GEN_FAILURE, and parms.hdr.result isn't changed.
617 *Before every call here we set it to VERR_WRONG_ORDER, so checking it here as well.
618 */
619 if (ERROR_GEN_FAILURE==lerr && VERR_WRONG_ORDER==((VBoxGuestHGCMCallInfo*)pvData)->result)
620 {
621 return VERR_OUT_OF_RANGE;
622 }
623 else
624 {
625 return VERR_NOT_SUPPORTED;
626 }
627# else
628 int rc;
629# if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
630 VBGLBIGREQ Hdr;
631 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
632 Hdr.cbData = cbData;
633 Hdr.pvDataR3 = pvData;
634# if HC_ARCH_BITS == 32
635 Hdr.u32Padding = 0;
636# endif
637 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), &Hdr);
638# else
639 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
640# endif
641# ifdef RT_OS_LINUX
642 if (rc == 0)
643# else
644 if (rc >= 0)
645# endif
646 {
647 return VINF_SUCCESS;
648 }
649# ifdef RT_OS_LINUX
650 if (rc >= 0) /* positive values are negated VBox error status codes. */
651 {
652 crWarning("vboxCall failed with VBox status code %d\n", -rc);
653 if (rc==VINF_INTERRUPTED)
654 {
655 RTMSINTERVAL sl;
656 int i;
657
658 for (i=0, sl=50; i<6; i++, sl=sl*2)
659 {
660 RTThreadSleep(sl);
661 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
662 if (rc==0)
663 {
664 crWarning("vboxCall retry(%i) succeeded", i+1);
665 return VINF_SUCCESS;
666 }
667 else if (rc==VINF_INTERRUPTED)
668 {
669 continue;
670 }
671 else
672 {
673 crWarning("vboxCall retry(%i) failed with VBox status code %d", i+1, -rc);
674 break;
675 }
676 }
677 }
678 return -rc;
679 }
680 else
681# endif
682 crWarning("vboxCall failed with %x\n", errno);
683 return VERR_NOT_SUPPORTED;
684# endif /*#ifdef RT_OS_WINDOWS*/
685
686#else /*#ifdef IN_GUEST*/
687 crError("crVBoxHGCMCall called on host side!");
688 CRASSERT(FALSE);
689 return VERR_NOT_SUPPORTED;
690#endif
691}
692
693static void *_crVBoxHGCMAlloc(CRConnection *conn)
694{
695 CRVBOXHGCMBUFFER *buf;
696
697#ifdef CHROMIUM_THREADSAFE
698 crLockMutex(&g_crvboxhgcm.mutex);
699#endif
700
701 buf = (CRVBOXHGCMBUFFER *) crBufferPoolPop(g_crvboxhgcm.bufpool, conn->buffer_size);
702
703 if (!buf)
704 {
705 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
706 (void *) g_crvboxhgcm.bufpool,
707 (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
708
709#if defined(IN_GUEST) && defined(RT_OS_WINDOWS)
710 /* Try to start DDRAW on guest side */
711 if (!g_crvboxhgcm.pDirectDraw && 0)
712 {
713 HRESULT hr;
714
715 hr = DirectDrawCreate(NULL, &g_crvboxhgcm.pDirectDraw, NULL);
716 if (hr != DD_OK)
717 {
718 crWarning("Failed to create DirectDraw interface (%x)\n", hr);
719 g_crvboxhgcm.pDirectDraw = NULL;
720 }
721 else
722 {
723 hr = IDirectDraw_SetCooperativeLevel(g_crvboxhgcm.pDirectDraw, NULL, DDSCL_NORMAL);
724 if (hr != DD_OK)
725 {
726 crWarning("Failed to SetCooperativeLevel (%x)\n", hr);
727 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
728 g_crvboxhgcm.pDirectDraw = NULL;
729 }
730 crDebug("Created DirectDraw and set CooperativeLevel successfully\n");
731 }
732 }
733
734 /* Try to allocate buffer via DDRAW */
735 if (g_crvboxhgcm.pDirectDraw)
736 {
737 DDSURFACEDESC ddsd;
738 HRESULT hr;
739 LPDIRECTDRAWSURFACE lpDDS;
740
741 memset(&ddsd, 0, sizeof(ddsd));
742 ddsd.dwSize = sizeof(ddsd);
743
744 /* @todo DDSCAPS_VIDEOMEMORY ain't working for some reason
745 * also, it would be better to request dwLinearSize but it fails too
746 * ddsd.dwLinearSize = sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size;
747 */
748
749 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
750 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
751 /* use 1 byte per pixel format */
752 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
753 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
754 ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
755 ddsd.ddpfPixelFormat.dwRBitMask = 0xFF;
756 ddsd.ddpfPixelFormat.dwGBitMask = 0;
757 ddsd.ddpfPixelFormat.dwBBitMask = 0;
758 /* request given buffer size, rounded to 1k */
759 ddsd.dwWidth = 1024;
760 ddsd.dwHeight = (sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size + ddsd.dwWidth-1)/ddsd.dwWidth;
761
762 hr = IDirectDraw_CreateSurface(g_crvboxhgcm.pDirectDraw, &ddsd, &lpDDS, NULL);
763 if (hr != DD_OK)
764 {
765 crWarning("Failed to create DirectDraw surface (%x)\n", hr);
766 }
767 else
768 {
769 crDebug("Created DirectDraw surface (%x)\n", lpDDS);
770
771 hr = IDirectDrawSurface_Lock(lpDDS, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL);
772 if (hr != DD_OK)
773 {
774 crWarning("Failed to lock DirectDraw surface (%x)\n", hr);
775 IDirectDrawSurface_Release(lpDDS);
776 }
777 else
778 {
779 uint32_t cbLocked;
780 cbLocked = (ddsd.dwFlags & DDSD_LINEARSIZE) ? ddsd.dwLinearSize : ddsd.lPitch*ddsd.dwHeight;
781
782 crDebug("Locked %d bytes DirectDraw surface\n", cbLocked);
783
784 buf = (CRVBOXHGCMBUFFER *) ddsd.lpSurface;
785 CRASSERT(buf);
786 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
787 buf->kind = CR_VBOXHGCM_DDRAW_SURFACE;
788 buf->allocated = cbLocked;
789 buf->pDDS = lpDDS;
790 }
791 }
792 }
793#endif
794
795 /* We're either on host side, or we failed to allocate DDRAW buffer */
796 if (!buf)
797 {
798 crDebug("Using system malloc\n");
799 buf = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size );
800 CRASSERT(buf);
801 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
802 buf->kind = CR_VBOXHGCM_MEMORY;
803 buf->allocated = conn->buffer_size;
804#ifdef RT_OS_WINDOWS
805 buf->pDDS = NULL;
806#endif
807 }
808 }
809
810#ifdef CHROMIUM_THREADSAFE
811 crUnlockMutex(&g_crvboxhgcm.mutex);
812#endif
813
814 return (void *)( buf + 1 );
815
816}
817
818static void *crVBoxHGCMAlloc(CRConnection *conn)
819{
820 void *pvBuff;
821 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
822#ifdef CHROMIUM_THREADSAFE
823 crLockMutex(&g_crvboxhgcm.mutex);
824#endif
825 pvBuff = _crVBoxHGCMAlloc(conn);
826#ifdef CHROMIUM_THREADSAFE
827 crUnlockMutex(&g_crvboxhgcm.mutex);
828#endif
829 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
830 return pvBuff;
831}
832
833static void _crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
834{
835 int rc;
836 int32_t callRes;
837
838#ifdef IN_GUEST
839 if (conn->u32InjectClientID)
840 {
841 CRVBOXHGCMINJECT parms;
842
843 parms.hdr.result = VERR_WRONG_ORDER;
844 parms.hdr.u32ClientID = conn->u32ClientID;
845 parms.hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
846 parms.hdr.cParms = SHCRGL_CPARMS_INJECT;
847
848 parms.u32ClientID.type = VMMDevHGCMParmType_32bit;
849 parms.u32ClientID.u.value32 = conn->u32InjectClientID;
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 else
859#endif
860 {
861 CRVBOXHGCMWRITE parms;
862
863 parms.hdr.result = VERR_WRONG_ORDER;
864 parms.hdr.u32ClientID = conn->u32ClientID;
865 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
866 parms.hdr.cParms = SHCRGL_CPARMS_WRITE;
867
868 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
869 parms.pBuffer.u.Pointer.size = len;
870 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
871
872 rc = crVBoxHGCMCall(&parms, sizeof(parms));
873 callRes = parms.hdr.result;
874 }
875
876 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
877 {
878 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
879 }
880}
881
882static void crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
883{
884 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
885#ifdef CHROMIUM_THREADSAFE
886 crLockMutex(&g_crvboxhgcm.mutex);
887#endif
888 _crVBoxHGCMWriteExact(conn, buf, len);
889#ifdef CHROMIUM_THREADSAFE
890 crUnlockMutex(&g_crvboxhgcm.mutex);
891#endif
892 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
893}
894
895static void crVBoxHGCMReadExact( CRConnection *conn, const void *buf, unsigned int len )
896{
897 CRVBOXHGCMREAD parms;
898 int rc;
899
900 parms.hdr.result = VERR_WRONG_ORDER;
901 parms.hdr.u32ClientID = conn->u32ClientID;
902 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
903 parms.hdr.cParms = SHCRGL_CPARMS_READ;
904
905 CRASSERT(!conn->pBuffer); //make sure there's no data to process
906 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
907 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
908 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
909
910 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
911 parms.cbBuffer.u.value32 = 0;
912
913 rc = crVBoxHGCMCall(&parms, sizeof(parms));
914
915 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
916 {
917 crWarning("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
918 return;
919 }
920
921 if (parms.cbBuffer.u.value32)
922 {
923 //conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
924 conn->pBuffer = conn->pHostBuffer;
925 conn->cbBuffer = parms.cbBuffer.u.value32;
926 }
927
928 if (conn->cbBuffer)
929 _crVBoxHGCMReceiveMessage(conn);
930
931}
932
933/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
934 * This halves the number of HGCM calls we do,
935 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
936 */
937static void
938crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, CRVBOXHGCMBUFFERKIND bufferKind)
939{
940 CRVBOXHGCMWRITEREAD parms;
941 int rc;
942
943 parms.hdr.result = VERR_WRONG_ORDER;
944 parms.hdr.u32ClientID = conn->u32ClientID;
945 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
946 parms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ;
947
948 //if (bufferKind != CR_VBOXHGCM_DDRAW_SURFACE)
949 {
950 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
951 parms.pBuffer.u.Pointer.size = len;
952 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
953 }
954 /*else ///@todo it fails badly, have to check why. bird: This fails because buf isn't a physical address?
955 {
956 parms.pBuffer.type = VMMDevHGCMParmType_PhysAddr;
957 parms.pBuffer.u.Pointer.size = len;
958 parms.pBuffer.u.Pointer.u.physAddr = (uintptr_t) buf;
959 }*/
960
961 CRASSERT(!conn->pBuffer); //make sure there's no data to process
962 parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out;
963 parms.pWriteback.u.Pointer.size = conn->cbHostBufferAllocated;
964 parms.pWriteback.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
965
966 parms.cbWriteback.type = VMMDevHGCMParmType_32bit;
967 parms.cbWriteback.u.value32 = 0;
968
969 rc = crVBoxHGCMCall(&parms, sizeof(parms));
970
971#if defined(RT_OS_LINUX) || defined(RT_OS_WINDOWS)
972 if (VERR_OUT_OF_RANGE==rc && CR_VBOXHGCM_USERALLOCATED==bufferKind)
973 {
974 /*Buffer is too big, so send it in split chunks*/
975 CRVBOXHGCMWRITEBUFFER wbParms;
976
977 wbParms.hdr.result = VERR_WRONG_ORDER;
978 wbParms.hdr.u32ClientID = conn->u32ClientID;
979 wbParms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_BUFFER;
980 wbParms.hdr.cParms = SHCRGL_CPARMS_WRITE_BUFFER;
981
982 wbParms.iBufferID.type = VMMDevHGCMParmType_32bit;
983 wbParms.iBufferID.u.value32 = 0;
984
985 wbParms.cbBufferSize.type = VMMDevHGCMParmType_32bit;
986 wbParms.cbBufferSize.u.value32 = len;
987
988 wbParms.ui32Offset.type = VMMDevHGCMParmType_32bit;
989 wbParms.ui32Offset.u.value32 = 0;
990
991 wbParms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
992 wbParms.pBuffer.u.Pointer.size = MIN(CR_HGCM_SPLIT_BUFFER_SIZE, len);
993 wbParms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
994
995 if (len<CR_HGCM_SPLIT_BUFFER_SIZE)
996 {
997 crError("VERR_OUT_OF_RANGE in crVBoxHGCMWriteReadExact for %u bytes write", len);
998 return;
999 }
1000
1001 while (wbParms.pBuffer.u.Pointer.size)
1002 {
1003 crDebug("SHCRGL_GUEST_FN_WRITE_BUFFER, offset=%u, size=%u", wbParms.ui32Offset.u.value32, wbParms.pBuffer.u.Pointer.size);
1004
1005 rc = crVBoxHGCMCall(&wbParms, sizeof(wbParms));
1006 if (RT_FAILURE(rc) || RT_FAILURE(wbParms.hdr.result))
1007 {
1008 crError("SHCRGL_GUEST_FN_WRITE_BUFFER (%i) failed with %x %x\n", wbParms.pBuffer.u.Pointer.size, rc, wbParms.hdr.result);
1009 return;
1010 }
1011
1012 wbParms.ui32Offset.u.value32 += wbParms.pBuffer.u.Pointer.size;
1013 wbParms.pBuffer.u.Pointer.u.linearAddr += (uintptr_t) wbParms.pBuffer.u.Pointer.size;
1014 wbParms.pBuffer.u.Pointer.size = MIN(CR_HGCM_SPLIT_BUFFER_SIZE, len-wbParms.ui32Offset.u.value32);
1015 }
1016
1017 /*now issue GUEST_FN_WRITE_READ_BUFFERED referencing the buffer we'd made*/
1018 {
1019 CRVBOXHGCMWRITEREADBUFFERED wrbParms;
1020
1021 wrbParms.hdr.result = VERR_WRONG_ORDER;
1022 wrbParms.hdr.u32ClientID = conn->u32ClientID;
1023 wrbParms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ_BUFFERED;
1024 wrbParms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ_BUFFERED;
1025
1026 crMemcpy(&wrbParms.iBufferID, &wbParms.iBufferID, sizeof(HGCMFunctionParameter));
1027 crMemcpy(&wrbParms.pWriteback, &parms.pWriteback, sizeof(HGCMFunctionParameter));
1028 crMemcpy(&wrbParms.cbWriteback, &parms.cbWriteback, sizeof(HGCMFunctionParameter));
1029
1030 rc = crVBoxHGCMCall(&wrbParms, sizeof(wrbParms));
1031
1032 /*bit of hack to reuse code below*/
1033 parms.hdr.result = wrbParms.hdr.result;
1034 crMemcpy(&parms.cbWriteback, &wrbParms.cbWriteback, sizeof(HGCMFunctionParameter));
1035 crMemcpy(&parms.pWriteback, &wrbParms.pWriteback, sizeof(HGCMFunctionParameter));
1036 }
1037 }
1038#endif
1039
1040 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1041 {
1042
1043 if ((VERR_BUFFER_OVERFLOW == parms.hdr.result) && RT_SUCCESS(rc))
1044 {
1045 /* reallocate buffer and retry */
1046
1047 CRASSERT(parms.cbWriteback.u.value32>conn->cbHostBufferAllocated);
1048
1049 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, parms.cbWriteback.u.value32);
1050
1051 crFree(conn->pHostBuffer);
1052 conn->cbHostBufferAllocated = parms.cbWriteback.u.value32;
1053 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
1054
1055 crVBoxHGCMReadExact(conn, buf, len);
1056
1057 return;
1058 }
1059 else
1060 {
1061 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x %x\n", len, rc, parms.hdr.result);
1062 return;
1063 }
1064 }
1065
1066 if (parms.cbWriteback.u.value32)
1067 {
1068 //conn->pBuffer = (uint8_t*) parms.pWriteback.u.Pointer.u.linearAddr;
1069 conn->pBuffer = conn->pHostBuffer;
1070 conn->cbBuffer = parms.cbWriteback.u.value32;
1071 }
1072
1073 if (conn->cbBuffer)
1074 _crVBoxHGCMReceiveMessage(conn);
1075}
1076
1077static void crVBoxHGCMSend(CRConnection *conn, void **bufp,
1078 const void *start, unsigned int len)
1079{
1080 CRVBOXHGCMBUFFER *hgcm_buffer;
1081 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1082
1083#ifdef CHROMIUM_THREADSAFE
1084 crLockMutex(&g_crvboxhgcm.mutex);
1085#endif
1086
1087 if (!bufp) /* We're sending a user-allocated buffer. */
1088 {
1089#ifndef IN_GUEST
1090 //@todo remove temp buffer allocation in unpacker
1091 /* we're at the host side, so just store data until guest polls us */
1092 _crVBoxHGCMWriteBytes(conn, start, len);
1093#else
1094 CRASSERT(!conn->u32InjectClientID);
1095 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
1096 crVBoxHGCMWriteReadExact(conn, start, len, CR_VBOXHGCM_USERALLOCATED);
1097#endif
1098#ifdef CHROMIUM_THREADSAFE
1099 crUnlockMutex(&g_crvboxhgcm.mutex);
1100#endif
1101 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1102 return;
1103 }
1104
1105 /* The region [start .. start + len + 1] lies within a buffer that
1106 * was allocated with crVBoxHGCMAlloc() and can be put into the free
1107 * buffer pool when we're done sending it.
1108 */
1109
1110 hgcm_buffer = (CRVBOXHGCMBUFFER *)(*bufp) - 1;
1111 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1112
1113 /* Length would be passed as part of HGCM pointer description
1114 * No need to prepend it to the buffer
1115 */
1116#ifdef IN_GUEST
1117 if (conn->u32InjectClientID)
1118 {
1119 _crVBoxHGCMWriteExact(conn, start, len);
1120 }
1121 else
1122#endif
1123 crVBoxHGCMWriteReadExact(conn, start, len, hgcm_buffer->kind);
1124
1125 /* Reclaim this pointer for reuse */
1126#ifdef CHROMIUM_THREADSAFE
1127 crLockMutex(&g_crvboxhgcm.mutex);
1128#endif
1129 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
1130#ifdef CHROMIUM_THREADSAFE
1131 crUnlockMutex(&g_crvboxhgcm.mutex);
1132#endif
1133
1134 /* Since the buffer's now in the 'free' buffer pool, the caller can't
1135 * use it any more. Setting bufp to NULL will make sure the caller
1136 * doesn't try to re-use the buffer.
1137 */
1138 *bufp = NULL;
1139
1140#ifdef CHROMIUM_THREADSAFE
1141 crUnlockMutex(&g_crvboxhgcm.mutex);
1142#endif
1143
1144 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1145}
1146
1147static void crVBoxHGCMPollHost(CRConnection *conn)
1148{
1149 CRVBOXHGCMREAD parms;
1150 int rc;
1151
1152 CRASSERT(!conn->pBuffer);
1153
1154 parms.hdr.result = VERR_WRONG_ORDER;
1155 parms.hdr.u32ClientID = conn->u32ClientID;
1156 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
1157 parms.hdr.cParms = SHCRGL_CPARMS_READ;
1158
1159 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
1160 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
1161 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
1162
1163 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
1164 parms.cbBuffer.u.value32 = 0;
1165
1166 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1167
1168 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1169 {
1170 crDebug("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
1171 return;
1172 }
1173
1174 if (parms.cbBuffer.u.value32)
1175 {
1176 conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
1177 conn->cbBuffer = parms.cbBuffer.u.value32;
1178 }
1179}
1180
1181static void crVBoxHGCMSingleRecv(CRConnection *conn, void *buf, unsigned int len)
1182{
1183 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1184#ifdef CHROMIUM_THREADSAFE
1185 crLockMutex(&g_crvboxhgcm.mutex);
1186#endif
1187 crVBoxHGCMReadExact(conn, buf, len);
1188#ifdef CHROMIUM_THREADSAFE
1189 crUnlockMutex(&g_crvboxhgcm.mutex);
1190#endif
1191 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1192}
1193
1194static void _crVBoxHGCMFree(CRConnection *conn, void *buf)
1195{
1196 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1197
1198 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1199
1200 /*@todo wrong len for redir buffers*/
1201 conn->recv_credits += hgcm_buffer->len;
1202
1203 switch (hgcm_buffer->kind)
1204 {
1205 case CR_VBOXHGCM_MEMORY:
1206#ifdef RT_OS_WINDOWS
1207 case CR_VBOXHGCM_DDRAW_SURFACE:
1208#endif
1209#ifdef CHROMIUM_THREADSAFE
1210 crLockMutex(&g_crvboxhgcm.mutex);
1211#endif
1212 if (g_crvboxhgcm.bufpool) {
1213 //@todo o'rly?
1214 /* pool may have been deallocated just a bit earlier in response
1215 * to a SIGPIPE (Broken Pipe) signal.
1216 */
1217 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
1218 }
1219#ifdef CHROMIUM_THREADSAFE
1220 crUnlockMutex(&g_crvboxhgcm.mutex);
1221#endif
1222 break;
1223
1224 case CR_VBOXHGCM_MEMORY_BIG:
1225 crFree( hgcm_buffer );
1226 break;
1227
1228 default:
1229 crError( "Weird buffer kind trying to free in crVBoxHGCMFree: %d", hgcm_buffer->kind );
1230 }
1231}
1232
1233static void crVBoxHGCMFree(CRConnection *conn, void *buf)
1234{
1235 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1236#ifdef CHROMIUM_THREADSAFE
1237 crLockMutex(&g_crvboxhgcm.mutex);
1238#endif
1239 _crVBoxHGCMFree(conn, buf);
1240#ifdef CHROMIUM_THREADSAFE
1241 crUnlockMutex(&g_crvboxhgcm.mutex);
1242#endif
1243 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1244}
1245
1246static void _crVBoxHGCMReceiveMessage(CRConnection *conn)
1247{
1248 uint32_t len;
1249 CRVBOXHGCMBUFFER *hgcm_buffer;
1250 CRMessage *msg;
1251 CRMessageType cached_type;
1252
1253 len = conn->cbBuffer;
1254 CRASSERT(len > 0);
1255 CRASSERT(conn->pBuffer);
1256
1257#ifndef IN_GUEST
1258 if (conn->allow_redir_ptr)
1259 {
1260#endif //IN_GUEST
1261 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
1262
1263 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1264 hgcm_buffer->len = sizeof(CRMessageRedirPtr);
1265
1266 msg = (CRMessage *) (hgcm_buffer + 1);
1267
1268 msg->header.type = CR_MESSAGE_REDIR_PTR;
1269 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
1270 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
1271
1272#if defined(VBOX_WITH_CRHGSMI) && !defined(IN_GUEST)
1273 msg->redirptr.CmdData = conn->CmdData;
1274 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&msg->redirptr.CmdData);
1275 CRVBOXHGSMI_CMDDATA_CLEANUP(&conn->CmdData);
1276#endif
1277
1278 cached_type = msg->redirptr.pMessage->type;
1279
1280 conn->cbBuffer = 0;
1281 conn->pBuffer = NULL;
1282#ifndef IN_GUEST
1283 }
1284 else
1285 {
1286 /* we should NEVER have redir_ptr disabled with HGSMI command now */
1287 CRASSERT(!conn->CmdData.pCmd);
1288 if ( len <= conn->buffer_size )
1289 {
1290 /* put in pre-allocated buffer */
1291 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1292 }
1293 else
1294 {
1295 /* allocate new buffer,
1296 * not using pool here as it's most likely one time transfer of huge texture
1297 */
1298 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
1299 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1300 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
1301 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
1302# ifdef RT_OS_WINDOWS
1303 hgcm_buffer->pDDS = NULL;
1304# endif
1305 }
1306
1307 hgcm_buffer->len = len;
1308 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
1309
1310 msg = (CRMessage *) (hgcm_buffer + 1);
1311 cached_type = msg->header.type;
1312 }
1313#endif //IN_GUEST
1314
1315 conn->recv_credits -= len;
1316 conn->total_bytes_recv += len;
1317 conn->recv_count++;
1318
1319 crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
1320
1321 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
1322 * OOB messages are the programmer's problem. -- Humper 12/17/01
1323 */
1324 if (cached_type != CR_MESSAGE_OPCODES
1325 && cached_type != CR_MESSAGE_OOB
1326 && cached_type != CR_MESSAGE_GATHER)
1327 {
1328 _crVBoxHGCMFree(conn, msg);
1329 }
1330}
1331
1332static void crVBoxHGCMReceiveMessage(CRConnection *conn)
1333{
1334 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1335#ifdef CHROMIUM_THREADSAFE
1336 crLockMutex(&g_crvboxhgcm.mutex);
1337#endif
1338 _crVBoxHGCMReceiveMessage(conn);
1339#ifdef CHROMIUM_THREADSAFE
1340 crUnlockMutex(&g_crvboxhgcm.mutex);
1341#endif
1342 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1343}
1344
1345
1346/*
1347 * Called on host side only, to "accept" client connection
1348 */
1349static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
1350{
1351 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1352 CRASSERT(conn && conn->pHostBuffer);
1353#ifdef IN_GUEST
1354 CRASSERT(FALSE);
1355#endif
1356 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1357}
1358
1359static int crVBoxHGCMSetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
1360{
1361 CRVBOXHGCMSETVERSION parms;
1362 int rc;
1363
1364 parms.hdr.result = VERR_WRONG_ORDER;
1365 parms.hdr.u32ClientID = conn->u32ClientID;
1366 parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_VERSION;
1367 parms.hdr.cParms = SHCRGL_CPARMS_SET_VERSION;
1368
1369 parms.vMajor.type = VMMDevHGCMParmType_32bit;
1370 parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
1371 parms.vMinor.type = VMMDevHGCMParmType_32bit;
1372 parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
1373
1374 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1375
1376 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1377 {
1378 crWarning("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
1379 parms.vMajor.u.value32, parms.vMinor.u.value32);
1380 return FALSE;
1381 }
1382
1383 conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
1384 conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
1385
1386 return TRUE;
1387}
1388
1389static int crVBoxHGCMSetPID(CRConnection *conn, unsigned long long pid)
1390{
1391 CRVBOXHGCMSETPID parms;
1392 int rc;
1393
1394 parms.hdr.result = VERR_WRONG_ORDER;
1395 parms.hdr.u32ClientID = conn->u32ClientID;
1396 parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_PID;
1397 parms.hdr.cParms = SHCRGL_CPARMS_SET_PID;
1398
1399 parms.u64PID.type = VMMDevHGCMParmType_64bit;
1400 parms.u64PID.u.value64 = pid;
1401
1402 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1403
1404 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1405 {
1406 crWarning("SHCRGL_GUEST_FN_SET_PID failed!");
1407 return FALSE;
1408 }
1409
1410 return TRUE;
1411}
1412
1413/**
1414 * The function that actually connects. This should only be called by clients,
1415 * guests in vbox case.
1416 * Servers go through crVBoxHGCMAccept;
1417 */
1418/*@todo use vbglR3Something here */
1419static int crVBoxHGCMDoConnect( CRConnection *conn )
1420{
1421#ifdef IN_GUEST
1422 VBoxGuestHGCMConnectInfo info;
1423
1424#ifdef RT_OS_WINDOWS
1425 DWORD cbReturned;
1426
1427 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1428
1429 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
1430 {
1431 /* open VBox guest driver */
1432 g_crvboxhgcm.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
1433 GENERIC_READ | GENERIC_WRITE,
1434 FILE_SHARE_READ | FILE_SHARE_WRITE,
1435 NULL,
1436 OPEN_EXISTING,
1437 FILE_ATTRIBUTE_NORMAL,
1438 NULL);
1439
1440 /* @todo check if we could rollback to softwareopengl */
1441 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
1442 {
1443 crDebug("could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
1444 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1445 return FALSE;
1446 }
1447 }
1448#else
1449 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1450 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
1451 {
1452 g_crvboxhgcm.iGuestDrv = open(VBOXGUEST_USER_DEVICE_NAME, O_RDWR, 0);
1453 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
1454 {
1455 crDebug("could not open Guest Additions kernel module! rc = %d\n", errno);
1456 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1457 return FALSE;
1458 }
1459 }
1460#endif
1461
1462 memset (&info, 0, sizeof (info));
1463 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
1464 strcpy (info.Loc.u.host.achName, "VBoxSharedCrOpenGL");
1465
1466#ifdef RT_OS_WINDOWS
1467 if (DeviceIoControl(g_crvboxhgcm.hGuestDrv,
1468 VBOXGUEST_IOCTL_HGCM_CONNECT,
1469 &info, sizeof (info),
1470 &info, sizeof (info),
1471 &cbReturned,
1472 NULL))
1473#elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1474 VBGLBIGREQ Hdr;
1475 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
1476 Hdr.cbData = sizeof(info);
1477 Hdr.pvDataR3 = &info;
1478# if HC_ARCH_BITS == 32
1479 Hdr.u32Padding = 0;
1480# endif
1481 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &Hdr) >= 0)
1482#else
1483 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info)) >= 0)
1484#endif
1485 {
1486 if (info.result == VINF_SUCCESS)
1487 {
1488 int rc;
1489 conn->u32ClientID = info.u32ClientID;
1490 crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
1491
1492 rc = crVBoxHGCMSetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
1493 if (!rc)
1494 {
1495 return rc;
1496 }
1497#ifdef RT_OS_WINDOWS
1498 rc = crVBoxHGCMSetPID(conn, GetCurrentProcessId());
1499#else
1500 rc = crVBoxHGCMSetPID(conn, crGetPID());
1501#endif
1502 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1503 return rc;
1504 }
1505 else
1506 {
1507 crDebug("HGCM connect failed with rc=0x%x\n", info.result);
1508
1509 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1510 return FALSE;
1511 }
1512 }
1513 else
1514 {
1515#ifdef RT_OS_WINDOWS
1516 DWORD winEr = GetLastError();
1517 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", winEr);
1518#else
1519 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", errno);
1520#endif
1521 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1522 return FALSE;
1523 }
1524
1525 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1526 return TRUE;
1527
1528#else /*#ifdef IN_GUEST*/
1529 crError("crVBoxHGCMDoConnect called on host side!");
1530 CRASSERT(FALSE);
1531 return FALSE;
1532#endif
1533}
1534
1535/*@todo same, replace DeviceIoControl with vbglR3DoIOCtl */
1536static void crVBoxHGCMDoDisconnect( CRConnection *conn )
1537{
1538#ifdef IN_GUEST
1539 VBoxGuestHGCMDisconnectInfo info;
1540# ifdef RT_OS_WINDOWS
1541 DWORD cbReturned;
1542# endif
1543 int i;
1544#endif
1545
1546 if (!g_crvboxhgcm.initialized) return;
1547
1548#ifdef CHROMIUM_THREADSAFE
1549 crLockMutex(&g_crvboxhgcm.mutex);
1550#endif
1551
1552 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1553
1554 if (conn->pHostBuffer)
1555 {
1556 crFree(conn->pHostBuffer);
1557 conn->pHostBuffer = NULL;
1558 conn->cbHostBuffer = 0;
1559 conn->cbHostBufferAllocated = 0;
1560 }
1561
1562 conn->pBuffer = NULL;
1563 conn->cbBuffer = 0;
1564
1565 if (conn->type == CR_VBOXHGCM)
1566 {
1567 --g_crvboxhgcm.num_conns;
1568
1569 if (conn->index < g_crvboxhgcm.num_conns)
1570 {
1571 g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
1572 g_crvboxhgcm.conns[conn->index]->index = conn->index;
1573 }
1574 else g_crvboxhgcm.conns[conn->index] = NULL;
1575
1576 conn->type = CR_NO_CONNECTION;
1577 }
1578
1579#ifndef IN_GUEST
1580#else /* IN_GUEST */
1581 if (conn->u32ClientID)
1582 {
1583 memset (&info, 0, sizeof (info));
1584 info.u32ClientID = conn->u32ClientID;
1585
1586# ifdef RT_OS_WINDOWS
1587 if ( !DeviceIoControl(g_crvboxhgcm.hGuestDrv,
1588 VBOXGUEST_IOCTL_HGCM_DISCONNECT,
1589 &info, sizeof (info),
1590 &info, sizeof (info),
1591 &cbReturned,
1592 NULL) )
1593 {
1594 crDebug("Disconnect failed with %x\n", GetLastError());
1595 }
1596# elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1597 VBGLBIGREQ Hdr;
1598 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
1599 Hdr.cbData = sizeof(info);
1600 Hdr.pvDataR3 = &info;
1601# if HC_ARCH_BITS == 32
1602 Hdr.u32Padding = 0;
1603# endif
1604 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Hdr) >= 0)
1605# else
1606 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info, sizeof (info)) < 0)
1607 {
1608 crDebug("Disconnect failed with %x\n", errno);
1609 }
1610# endif
1611
1612 conn->u32ClientID = 0;
1613 }
1614
1615 /* see if any connections remain */
1616 for (i = 0; i < g_crvboxhgcm.num_conns; i++)
1617 if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
1618 break;
1619
1620 /* close guest additions driver*/
1621 if (i>=g_crvboxhgcm.num_conns)
1622 {
1623# ifdef RT_OS_WINDOWS
1624 CloseHandle(g_crvboxhgcm.hGuestDrv);
1625 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
1626# else
1627 close(g_crvboxhgcm.iGuestDrv);
1628 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
1629# endif
1630 }
1631#endif /* IN_GUEST */
1632
1633 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1634
1635#ifdef CHROMIUM_THREADSAFE
1636 crUnlockMutex(&g_crvboxhgcm.mutex);
1637#endif
1638}
1639
1640static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
1641{
1642 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1643#ifdef CHROMIUM_THREADSAFE
1644 crLockMutex(&g_crvboxhgcm.mutex);
1645#endif
1646 _crVBoxHGCMFree(conn, mess);
1647 CRASSERT(FALSE);
1648#ifdef CHROMIUM_THREADSAFE
1649 crUnlockMutex(&g_crvboxhgcm.mutex);
1650#endif
1651 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1652}
1653
1654static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1655{
1656 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1657 CRASSERT(FALSE);
1658 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1659}
1660
1661#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1662
1663bool _crVBoxHGSMIInit()
1664{
1665#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1666 static
1667#endif
1668 int bHasHGSMI = -1;
1669
1670 if (bHasHGSMI < 0)
1671 {
1672 int rc;
1673#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1674 rc = VBoxCrHgsmiInit();
1675#else
1676 VBOXCRHGSMI_CALLBACKS Callbacks;
1677 Callbacks.pfnClientCreate = _crVBoxHGSMIClientCreate;
1678 Callbacks.pfnClientDestroy = _crVBoxHGSMIClientDestroy;
1679 rc = VBoxCrHgsmiInit(&Callbacks);
1680#endif
1681 if (RT_SUCCESS(rc))
1682 bHasHGSMI = 1;
1683 else
1684 bHasHGSMI = 0;
1685
1686 crDebug("CrHgsmi is %s", bHasHGSMI ? "ENABLED" : "DISABLED");
1687 }
1688
1689 CRASSERT(bHasHGSMI >= 0);
1690
1691 return bHasHGSMI;
1692}
1693
1694void _crVBoxHGSMITearDown()
1695{
1696 VBoxCrHgsmiTerm();
1697}
1698
1699static void *_crVBoxHGSMIDoAlloc(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1700{
1701 PVBOXUHGSMI_BUFFER buf;
1702 CRVBOXHGCMBUFFER *pData = NULL;
1703 uint32_t cbSize = conn->buffer_size;
1704 int rc;
1705
1706 buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
1707 CRASSERT(buf);
1708 if (buf)
1709 {
1710 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1711 buf->pvUserData = pClient;
1712 fFlags.Value = 0;
1713 fFlags.bDiscard = 1;
1714 rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
1715 if (RT_SUCCESS(rc))
1716 {
1717 pData->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1718 pData->kind = CR_VBOXHGCM_UHGSMI_BUFFER;
1719 pData->pBuffer = buf;
1720 }
1721 else
1722 {
1723 crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
1724 }
1725 return CRVBOXHGSMI_BUF_DATA(pData);
1726 }
1727
1728 /* fall back */
1729 return _crVBoxHGCMAlloc(conn);
1730}
1731
1732static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
1733{
1734 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1735
1736 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1737
1738 if (hgcm_buffer->kind == CR_VBOXHGCM_UHGSMI_BUFFER)
1739 {
1740 PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1741 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1742 pBuf->pfnUnlock(pBuf);
1743 _crVBoxHGSMIBufFree(pClient, pBuf);
1744 }
1745 else
1746 {
1747 _crVBoxHGCMFree(conn, buf);
1748 }
1749}
1750
1751static void *crVBoxHGSMIAlloc(CRConnection *conn)
1752{
1753 PCRVBOXHGSMI_CLIENT pClient;
1754 void *pvBuf;
1755
1756 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1757
1758#ifdef CHROMIUM_THREADSAFE
1759 crLockMutex(&g_crvboxhgcm.mutex);
1760#endif
1761
1762 pClient = _crVBoxHGSMIClientGet(conn);
1763 if (pClient)
1764 {
1765 pvBuf = _crVBoxHGSMIDoAlloc(conn, pClient);
1766 CRASSERT(pvBuf);
1767 }
1768 else
1769 {
1770 pvBuf = _crVBoxHGCMAlloc(conn);
1771 }
1772
1773#ifdef CHROMIUM_THREADSAFE
1774 crUnlockMutex(&g_crvboxhgcm.mutex);
1775#endif
1776
1777 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1778
1779 return pvBuf;
1780}
1781
1782static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
1783{
1784 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1785#ifdef CHROMIUM_THREADSAFE
1786 crLockMutex(&g_crvboxhgcm.mutex);
1787#endif
1788 _crVBoxHGSMIFree(conn, buf);
1789#ifdef CHROMIUM_THREADSAFE
1790 crUnlockMutex(&g_crvboxhgcm.mutex);
1791#endif
1792 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1793}
1794
1795static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1796{
1797 CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1798 int rc;
1799 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1800 PVBOXUHGSMI_BUFFER pRecvBuffer;
1801 uint32_t cbBuffer;
1802
1803 CRASSERT(parms);
1804
1805 parms->hdr.result = VERR_WRONG_ORDER;
1806 parms->hdr.u32ClientID = conn->u32ClientID;
1807 parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
1808// parms->hdr.u32Reserved = 0;
1809
1810 CRASSERT(!conn->pBuffer); //make sure there's no data to process
1811 parms->iBuffer = 1;
1812 parms->cbBuffer = 0;
1813
1814 _crVBoxHGSMICmdBufferUnlock(pClient);
1815
1816 pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1817 CRASSERT(pRecvBuffer);
1818 if (!pRecvBuffer)
1819 return;
1820
1821 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1822
1823 aSubmit[1].pBuf = pRecvBuffer;
1824 aSubmit[1].offData = 0;
1825 aSubmit[1].cbData = pRecvBuffer->cbBuffer;
1826 aSubmit[1].fFlags.Value = 0;
1827 aSubmit[1].fFlags.bHostWriteOnly = 1;
1828
1829 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
1830 AssertRC(rc);
1831 if (RT_FAILURE(rc))
1832 {
1833 crError("pfnBufferSubmitAsynch failed with %d \n", rc);
1834 return;
1835 }
1836
1837 _crVBoxHGSMIWaitCmd(pClient);
1838
1839 parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1840 CRASSERT(parms);
1841 if (!parms)
1842 {
1843 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1844 return;
1845 }
1846
1847 if (RT_SUCCESS(parms->hdr.result))
1848 cbBuffer = parms->cbBuffer;
1849 else
1850 cbBuffer = 0;
1851
1852 _crVBoxHGSMICmdBufferUnlock(pClient);
1853
1854 if (cbBuffer)
1855 {
1856 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
1857 CRASSERT(pvData);
1858 if (pvData)
1859 {
1860 conn->pBuffer = pvData;
1861 conn->cbBuffer = cbBuffer;
1862 }
1863 }
1864}
1865
1866static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1867{
1868 _crVBoxHGSMIPollHost(conn, pClient);
1869
1870 if (conn->cbBuffer)
1871 _crVBoxHGCMReceiveMessage(conn);
1872}
1873
1874/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
1875 * This halves the number of HGCM calls we do,
1876 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
1877 */
1878static void
1879_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
1880{
1881 CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1882 int rc;
1883 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
1884 PVBOXUHGSMI_BUFFER pBuf = NULL;
1885 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1886// uint32_t cbBuffer;
1887
1888 parms->hdr.result = VERR_WRONG_ORDER;
1889 parms->hdr.u32ClientID = conn->u32ClientID;
1890 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
1891// parms->hdr.u32Reserved = 0;
1892
1893 parms->iBuffer = 1;
1894
1895 CRASSERT(!conn->pBuffer); //make sure there's no data to process
1896 parms->iWriteback = 2;
1897 parms->cbWriteback = 0;
1898
1899 _crVBoxHGSMICmdBufferUnlock(pClient);
1900
1901 if (!bIsBuffer)
1902 {
1903 void *pvBuf;
1904 pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
1905
1906 if (!pBuf)
1907 {
1908 /* fallback */
1909 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1910 return;
1911 }
1912
1913 CRASSERT(!offBuffer);
1914
1915 offBuffer = 0;
1916 fFlags.Value = 0;
1917 fFlags.bDiscard = 1;
1918 fFlags.bWriteOnly = 1;
1919 rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
1920 AssertRC(rc);
1921 if (RT_SUCCESS(rc))
1922 {
1923 memcpy(pvBuf, buf, len);
1924 rc = pBuf->pfnUnlock(pBuf);
1925 AssertRC(rc);
1926 CRASSERT(RT_SUCCESS(rc));
1927 }
1928 else
1929 {
1930 _crVBoxHGSMIBufFree(pClient, pBuf);
1931 /* fallback */
1932 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1933 return;
1934 }
1935 }
1936 else
1937 {
1938 pBuf = (PVBOXUHGSMI_BUFFER)buf;
1939 }
1940
1941 do
1942 {
1943 PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1944 CRASSERT(pRecvBuffer);
1945 if (!pRecvBuffer)
1946 {
1947 break;
1948 }
1949
1950 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1951
1952 aSubmit[1].pBuf = pBuf;
1953 aSubmit[1].offData = offBuffer;
1954 aSubmit[1].cbData = len;
1955 aSubmit[1].fFlags.Value = 0;
1956 aSubmit[1].fFlags.bHostReadOnly = 1;
1957
1958 aSubmit[2].pBuf = pRecvBuffer;
1959 aSubmit[2].offData = 0;
1960 aSubmit[2].cbData = pRecvBuffer->cbBuffer;
1961 aSubmit[2].fFlags.Value = 0;
1962
1963 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 3);
1964 AssertRC(rc);
1965 if (RT_FAILURE(rc))
1966 {
1967 crError("pfnBufferSubmitAsynch failed with %d \n", rc);
1968 break;
1969 }
1970
1971 _crVBoxHGSMIWaitCmd(pClient);
1972
1973 parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1974 CRASSERT(parms);
1975 if (parms)
1976 {
1977 uint32_t cbWriteback = parms->cbWriteback;
1978 rc = parms->hdr.result;
1979 _crVBoxHGSMICmdBufferUnlock(pClient);
1980#ifdef DEBUG
1981 parms = NULL;
1982#endif
1983 if (RT_SUCCESS(rc))
1984 {
1985 if (cbWriteback)
1986 {
1987 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
1988 CRASSERT(pvData);
1989 if (pvData)
1990 {
1991 conn->pBuffer = pvData;
1992 conn->cbBuffer = cbWriteback;
1993 _crVBoxHGCMReceiveMessage(conn);
1994 }
1995 }
1996 }
1997 else if (VERR_BUFFER_OVERFLOW == rc)
1998 {
1999 PVBOXUHGSMI_BUFFER pOldBuf = pClient->pHGBuffer;
2000 CRASSERT(!pClient->pvHGBuffer);
2001 CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
2002 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
2003
2004 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback),
2005 VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL, &pClient->pHGBuffer);
2006 AssertRC(rc);
2007 CRASSERT(RT_SUCCESS(rc));
2008 if (RT_SUCCESS(rc))
2009 {
2010 rc = pOldBuf->pfnDestroy(pOldBuf);
2011 CRASSERT(RT_SUCCESS(rc));
2012
2013 _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
2014 }
2015 else
2016 {
2017 crFree(conn->pHostBuffer);
2018 conn->cbHostBufferAllocated = cbWriteback;
2019 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
2020 crVBoxHGCMReadExact(conn, NULL, cbWriteback);
2021 }
2022 }
2023 else
2024 {
2025 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
2026 }
2027 }
2028 else
2029 {
2030 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
2031 break;
2032 }
2033 } while (0);
2034
2035 if (!bIsBuffer)
2036 _crVBoxHGSMIBufFree(pClient, pBuf);
2037
2038 return;
2039}
2040
2041static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
2042{
2043 int rc;
2044 int32_t callRes;
2045 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
2046
2047#ifdef IN_GUEST
2048 if (conn->u32InjectClientID)
2049 {
2050 CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
2051 CRASSERT(parms);
2052 if (!parms)
2053 {
2054 return;
2055 }
2056
2057 parms->hdr.result = VERR_WRONG_ORDER;
2058 parms->hdr.u32ClientID = conn->u32ClientID;
2059 parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
2060// parms->hdr.u32Reserved = 0;
2061
2062 parms->u32ClientID = conn->u32InjectClientID;
2063
2064 parms->iBuffer = 1;
2065 _crVBoxHGSMICmdBufferUnlock(pClient);
2066
2067 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
2068
2069 aSubmit[1].pBuf = pBuf;
2070 aSubmit[1].offData = offStart;
2071 aSubmit[1].cbData = len;
2072 aSubmit[1].fFlags.Value = 0;
2073 aSubmit[1].fFlags.bHostReadOnly = 1;
2074
2075 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
2076 AssertRC(rc);
2077 if (RT_SUCCESS(rc))
2078 {
2079 _crVBoxHGSMIWaitCmd(pClient);
2080 /* @todo: do we need to wait for completion actually?
2081 * NOTE: in case we do not need completion,
2082 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
2083// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
2084
2085 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
2086 }
2087 else
2088 {
2089 /* we can not recover at this point, report error & exit */
2090 crError("pfnBufferSubmitAsynch failed with %d \n", rc);
2091 }
2092 }
2093 else
2094#endif
2095 {
2096 CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
2097
2098 parms->hdr.result = VERR_WRONG_ORDER;
2099 parms->hdr.u32ClientID = conn->u32ClientID;
2100 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
2101// parms->hdr.u32Reserved = 0;
2102
2103 parms->iBuffer = 1;
2104 _crVBoxHGSMICmdBufferUnlock(pClient);
2105
2106 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
2107
2108 aSubmit[1].pBuf = pBuf;
2109 aSubmit[1].offData = offStart;
2110 aSubmit[1].cbData = len;
2111 aSubmit[1].fFlags.Value = 0;
2112 aSubmit[1].fFlags.bHostReadOnly = 1;
2113
2114 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
2115 AssertRC(rc);
2116 if (RT_SUCCESS(rc))
2117 {
2118 _crVBoxHGSMIWaitCmd(pClient);
2119 /* @todo: do we need to wait for completion actually?
2120 * NOTE: in case we do not need completion,
2121 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
2122// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
2123
2124 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
2125 }
2126 else
2127 {
2128 /* we can not recover at this point, report error & exit */
2129 crError("Failed to submit CrHhgsmi buffer");
2130 }
2131 }
2132
2133 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
2134 {
2135 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
2136 }
2137}
2138
2139static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
2140 const void *start, unsigned int len)
2141{
2142 PCRVBOXHGSMI_CLIENT pClient;
2143 PVBOXUHGSMI_BUFFER pBuf;
2144 CRVBOXHGCMBUFFER *hgcm_buffer;
2145
2146 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2147
2148#ifdef CHROMIUM_THREADSAFE
2149 crLockMutex(&g_crvboxhgcm.mutex);
2150#endif
2151
2152 if (!bufp) /* We're sending a user-allocated buffer. */
2153 {
2154 pClient = _crVBoxHGSMIClientGet(conn);
2155 if (pClient)
2156 {
2157#ifndef IN_GUEST
2158 //@todo remove temp buffer allocation in unpacker
2159 /* we're at the host side, so just store data until guest polls us */
2160 _crVBoxHGCMWriteBytes(conn, start, len);
2161#else
2162 CRASSERT(!conn->u32InjectClientID);
2163 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
2164 _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
2165#endif
2166#ifdef CHROMIUM_THREADSAFE
2167 crUnlockMutex(&g_crvboxhgcm.mutex);
2168#endif
2169 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2170 return;
2171 }
2172
2173 /* fallback */
2174 crVBoxHGCMSend(conn, bufp, start, len);
2175#ifdef CHROMIUM_THREADSAFE
2176 crUnlockMutex(&g_crvboxhgcm.mutex);
2177#endif
2178 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2179 return;
2180 }
2181
2182 hgcm_buffer = (CRVBOXHGCMBUFFER *) *bufp - 1;
2183 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2184 if (hgcm_buffer->magic != CR_VBOXHGCM_BUFFER_MAGIC)
2185 {
2186 crError("HGCM buffer magic mismatch");
2187 }
2188
2189
2190 if (hgcm_buffer->kind != CR_VBOXHGCM_UHGSMI_BUFFER)
2191 {
2192 /* fallback */
2193 crVBoxHGCMSend(conn, bufp, start, len);
2194#ifdef CHROMIUM_THREADSAFE
2195 crUnlockMutex(&g_crvboxhgcm.mutex);
2196#endif
2197 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2198 return;
2199 }
2200
2201 /* The region [start .. start + len + 1] lies within a buffer that
2202 * was allocated with crVBoxHGCMAlloc() and can be put into the free
2203 * buffer pool when we're done sending it.
2204 */
2205
2206 pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
2207 CRASSERT(pBuf);
2208 if (!pBuf)
2209 {
2210 crVBoxHGCMSend(conn, bufp, start, len);
2211#ifdef CHROMIUM_THREADSAFE
2212 crUnlockMutex(&g_crvboxhgcm.mutex);
2213#endif
2214 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2215 return;
2216 }
2217
2218 pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
2219 if (pClient != &conn->HgsmiClient)
2220 {
2221 crError("HGSMI client mismatch");
2222 }
2223
2224 /* Length would be passed as part of HGCM pointer description
2225 * No need to prepend it to the buffer
2226 */
2227#ifdef IN_GUEST
2228 if (conn->u32InjectClientID)
2229 {
2230 _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
2231 }
2232 else
2233#endif
2234 {
2235 _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
2236 }
2237
2238 /* Reclaim this pointer for reuse */
2239 _crVBoxHGSMIBufFree(pClient, pBuf);
2240 /* Since the buffer's now in the 'free' buffer pool, the caller can't
2241 * use it any more. Setting bufp to NULL will make sure the caller
2242 * doesn't try to re-use the buffer.
2243 */
2244 *bufp = NULL;
2245
2246#ifdef CHROMIUM_THREADSAFE
2247 crUnlockMutex(&g_crvboxhgcm.mutex);
2248#endif
2249
2250 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2251}
2252
2253static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
2254{
2255 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2256
2257 CRASSERT(0);
2258
2259 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2260}
2261
2262static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
2263{
2264 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2265
2266 CRASSERT(0);
2267
2268 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2269}
2270
2271static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
2272{
2273 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2274
2275#ifdef CHROMIUM_THREADSAFE
2276 crLockMutex(&g_crvboxhgcm.mutex);
2277#endif
2278
2279 CRASSERT(0);
2280
2281 _crVBoxHGCMReceiveMessage(conn);
2282
2283#ifdef CHROMIUM_THREADSAFE
2284 crUnlockMutex(&g_crvboxhgcm.mutex);
2285#endif
2286
2287 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2288}
2289
2290/*
2291 * Called on host side only, to "accept" client connection
2292 */
2293static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
2294{
2295 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2296 CRASSERT(0);
2297
2298 CRASSERT(conn && conn->pHostBuffer);
2299#ifdef IN_GUEST
2300 CRASSERT(FALSE);
2301#endif
2302 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2303}
2304
2305static int crVBoxHGSMIDoConnect( CRConnection *conn )
2306{
2307 return crVBoxHGCMDoConnect(conn);
2308}
2309
2310static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
2311{
2312#ifdef CHROMIUM_THREADSAFE
2313 crLockMutex(&g_crvboxhgcm.mutex);
2314#endif
2315#ifndef VBOX_CRHGSMI_WITH_D3DDEV
2316 if (conn->HgsmiClient.pHgsmi)
2317 {
2318 PVBOXUHGSMI pHgsmi;
2319 _crVBoxHGSMIClientTerm(&conn->HgsmiClient, &pHgsmi);
2320 CRASSERT(pHgsmi);
2321 VBoxCrHgsmiDestroy(pHgsmi);
2322 }
2323#endif
2324 crVBoxHGCMDoDisconnect(conn);
2325#ifdef CHROMIUM_THREADSAFE
2326 crUnlockMutex(&g_crvboxhgcm.mutex);
2327#endif
2328}
2329
2330static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
2331{
2332 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2333#ifdef CHROMIUM_THREADSAFE
2334 crLockMutex(&g_crvboxhgcm.mutex);
2335#endif
2336 CRASSERT(0);
2337
2338 _crVBoxHGSMIFree(conn, mess);
2339
2340#ifdef CHROMIUM_THREADSAFE
2341 crUnlockMutex(&g_crvboxhgcm.mutex);
2342#endif
2343 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2344}
2345
2346static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
2347{
2348 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2349 CRASSERT(0);
2350
2351 CRASSERT(FALSE);
2352 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2353}
2354#endif
2355
2356void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
2357{
2358 (void) mtu;
2359
2360 g_crvboxhgcm.recv_list = rfl;
2361 g_crvboxhgcm.close_list = cfl;
2362 if (g_crvboxhgcm.initialized)
2363 {
2364 return;
2365 }
2366
2367 VBOXCRHGSMIPROFILE_INIT();
2368
2369 g_crvboxhgcm.initialized = 1;
2370
2371#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2372 g_crvboxhgcm.bHgsmiOn = _crVBoxHGSMIInit();
2373#endif
2374
2375 g_crvboxhgcm.num_conns = 0;
2376 g_crvboxhgcm.conns = NULL;
2377
2378 /* Can't open VBox guest driver here, because it gets called for host side as well */
2379 /*@todo as we have 2 dll versions, can do it now.*/
2380
2381#ifdef RT_OS_WINDOWS
2382 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
2383 g_crvboxhgcm.pDirectDraw = NULL;
2384#else
2385 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
2386#endif
2387
2388#ifdef CHROMIUM_THREADSAFE
2389 crInitMutex(&g_crvboxhgcm.mutex);
2390 crInitMutex(&g_crvboxhgcm.recvmutex);
2391#endif
2392 g_crvboxhgcm.bufpool = crBufferPoolInit(16);
2393}
2394
2395/* Callback function used to free buffer pool entries */
2396void crVBoxHGCMBufferFree(void *data)
2397{
2398#ifdef RT_OS_WINDOWS
2399 LPDIRECTDRAWSURFACE lpDDS;
2400#endif
2401 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
2402
2403 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2404
2405 switch (hgcm_buffer->kind)
2406 {
2407 case CR_VBOXHGCM_MEMORY:
2408 crFree( hgcm_buffer );
2409 break;
2410#ifdef RT_OS_WINDOWS
2411 case CR_VBOXHGCM_DDRAW_SURFACE:
2412 lpDDS = hgcm_buffer->pDDS;
2413 CRASSERT(lpDDS);
2414 IDirectDrawSurface_Unlock(lpDDS, NULL);
2415 IDirectDrawSurface_Release(lpDDS);
2416 crDebug("DDraw surface freed (%x)\n", lpDDS);
2417 break;
2418#endif
2419 case CR_VBOXHGCM_MEMORY_BIG:
2420 crFree( hgcm_buffer );
2421 break;
2422
2423 default:
2424 crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
2425 }
2426}
2427
2428void crVBoxHGCMTearDown(void)
2429{
2430 int32_t i, cCons;
2431
2432 if (!g_crvboxhgcm.initialized) return;
2433
2434#ifdef CHROMIUM_THREADSAFE
2435 crLockMutex(&g_crvboxhgcm.mutex);
2436#endif
2437
2438 /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
2439 * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
2440 * order of their connection.
2441 */
2442 cCons = g_crvboxhgcm.num_conns;
2443 for (i=0; i<cCons; i++)
2444 {
2445 /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
2446 crNetDisconnect(g_crvboxhgcm.conns[0]);
2447 }
2448 CRASSERT(0==g_crvboxhgcm.num_conns);
2449
2450 g_crvboxhgcm.initialized = 0;
2451
2452#ifdef CHROMIUM_THREADSAFE
2453 crUnlockMutex(&g_crvboxhgcm.mutex);
2454 crFreeMutex(&g_crvboxhgcm.mutex);
2455 crFreeMutex(&g_crvboxhgcm.recvmutex);
2456#endif
2457
2458 if (g_crvboxhgcm.bufpool)
2459 crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
2460 g_crvboxhgcm.bufpool = NULL;
2461
2462 crFree(g_crvboxhgcm.conns);
2463 g_crvboxhgcm.conns = NULL;
2464
2465#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2466 if (g_crvboxhgcm.bHgsmiOn)
2467 {
2468 _crVBoxHGSMITearDown();
2469 }
2470#endif
2471
2472#ifdef RT_OS_WINDOWS
2473 if (g_crvboxhgcm.pDirectDraw)
2474 {
2475 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
2476 g_crvboxhgcm.pDirectDraw = NULL;
2477 crDebug("DirectDraw released\n");
2478 }
2479#endif
2480}
2481
2482void crVBoxHGCMConnection(CRConnection *conn)
2483{
2484 int i, found = 0;
2485 int n_bytes;
2486
2487 CRASSERT(g_crvboxhgcm.initialized);
2488
2489#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2490 if (g_crvboxhgcm.bHgsmiOn)
2491 {
2492 conn->type = CR_VBOXHGCM;
2493 conn->Alloc = crVBoxHGSMIAlloc;
2494 conn->Send = crVBoxHGSMISend;
2495 conn->SendExact = crVBoxHGSMIWriteExact;
2496 conn->Recv = crVBoxHGSMISingleRecv;
2497 conn->RecvMsg = crVBoxHGSMIReceiveMessage;
2498 conn->Free = crVBoxHGSMIFree;
2499 conn->Accept = crVBoxHGSMIAccept;
2500 conn->Connect = crVBoxHGSMIDoConnect;
2501 conn->Disconnect = crVBoxHGSMIDoDisconnect;
2502 conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
2503 conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
2504 }
2505 else
2506#endif
2507 {
2508 conn->type = CR_VBOXHGCM;
2509 conn->Alloc = crVBoxHGCMAlloc;
2510 conn->Send = crVBoxHGCMSend;
2511 conn->SendExact = crVBoxHGCMWriteExact;
2512 conn->Recv = crVBoxHGCMSingleRecv;
2513 conn->RecvMsg = crVBoxHGCMReceiveMessage;
2514 conn->Free = crVBoxHGCMFree;
2515 conn->Accept = crVBoxHGCMAccept;
2516 conn->Connect = crVBoxHGCMDoConnect;
2517 conn->Disconnect = crVBoxHGCMDoDisconnect;
2518 conn->InstantReclaim = crVBoxHGCMInstantReclaim;
2519 conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
2520 }
2521 conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
2522 conn->actual_network = 1;
2523
2524 conn->krecv_buf_size = 0;
2525
2526 conn->pBuffer = NULL;
2527 conn->cbBuffer = 0;
2528 conn->allow_redir_ptr = 1;
2529
2530 //@todo remove this crap at all later
2531 conn->cbHostBufferAllocated = 2*1024;
2532 conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
2533 CRASSERT(conn->pHostBuffer);
2534 conn->cbHostBuffer = 0;
2535
2536#ifdef CHROMIUM_THREADSAFE
2537 crLockMutex(&g_crvboxhgcm.mutex);
2538#endif
2539 /* Find a free slot */
2540 for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
2541 if (g_crvboxhgcm.conns[i] == NULL) {
2542 conn->index = i;
2543 g_crvboxhgcm.conns[i] = conn;
2544 found = 1;
2545 break;
2546 }
2547 }
2548
2549 /* Realloc connection stack if we couldn't find a free slot */
2550 if (found == 0) {
2551 n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
2552 crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
2553 conn->index = g_crvboxhgcm.num_conns;
2554 g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
2555 }
2556#ifdef CHROMIUM_THREADSAFE
2557 crUnlockMutex(&g_crvboxhgcm.mutex);
2558#endif
2559}
2560
2561int crVBoxHGCMRecv(void)
2562{
2563 int32_t i;
2564
2565 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2566
2567#ifdef CHROMIUM_THREADSAFE
2568 crLockMutex(&g_crvboxhgcm.mutex);
2569#endif
2570
2571#ifdef IN_GUEST
2572 /* we're on guest side, poll host if it got something for us */
2573 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2574 {
2575 CRConnection *conn = g_crvboxhgcm.conns[i];
2576
2577 if ( !conn || conn->type == CR_NO_CONNECTION )
2578 continue;
2579
2580 if (!conn->pBuffer)
2581 {
2582#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2583 PCRVBOXHGSMI_CLIENT pClient;
2584 if (g_crvboxhgcm.bHgsmiOn && !!(pClient = _crVBoxHGSMIClientGet(conn)))
2585 {
2586 _crVBoxHGSMIPollHost(conn, pClient);
2587 }
2588 else
2589#endif
2590 {
2591 crVBoxHGCMPollHost(conn);
2592 }
2593 }
2594 }
2595#endif
2596
2597 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2598 {
2599 CRConnection *conn = g_crvboxhgcm.conns[i];
2600
2601 if ( !conn || conn->type == CR_NO_CONNECTION )
2602 continue;
2603
2604 if (conn->cbBuffer>0)
2605 {
2606 _crVBoxHGCMReceiveMessage(conn);
2607 }
2608 }
2609
2610#ifdef CHROMIUM_THREADSAFE
2611 crUnlockMutex(&g_crvboxhgcm.mutex);
2612#endif
2613
2614 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2615
2616 return 0;
2617}
2618
2619CRConnection** crVBoxHGCMDump( int *num )
2620{
2621 *num = g_crvboxhgcm.num_conns;
2622
2623 return g_crvboxhgcm.conns;
2624}
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