VirtualBox

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

Last change on this file since 49591 was 49591, checked in by vboxsync, 11 years ago

wddm: more on new comand mechanism, guest side almost done, some cleanup

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