VirtualBox

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

Last change on this file since 69500 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use