VirtualBox

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

Last change on this file since 78493 was 78341, checked in by vboxsync, 6 years ago

Config.kmk,Additions/common/crOpenGL,VBox/GuestHost/OpenGL,HostServices/SharedOpenGL: Remove CHROMIUM_THREADSAFE define and apply the current default

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

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