VirtualBox

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

Last change on this file since 79241 was 78791, checked in by vboxsync, 6 years ago

GuestHost/OpenGL/util/vboxhgcm.c: Avoid a warning which is expected certain read requests

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