VirtualBox

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

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

WDDM/3d: remove assert

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