VirtualBox

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

Last change on this file since 78116 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.2 KB
Line 
1/* $Id: vboxhgcm.c 76553 2019-01-01 01:45:53Z 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_endian.h"
35#include "cr_threads.h"
36#include "net_internals.h"
37#include "cr_process.h"
38
39#include <iprt/initterm.h>
40#include <iprt/thread.h>
41
42#include <VBox/VBoxGuestLib.h>
43#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
44
45#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
46#include <VBoxCrHgsmi.h>
47#endif
48
49/** @todo move define somewhere else, and make sure it's less than VBGLR0_MAX_HGCM_KERNEL_PARM*/
50/*If we fail to pass data in one chunk, send it in chunks of this size instead*/
51#define CR_HGCM_SPLIT_BUFFER_SIZE (8*_1M)
52
53#ifndef MIN
54# define MIN(a, b) ((a) < (b) ? (a) : (b))
55#endif
56
57#ifdef DEBUG_misha
58#ifdef CRASSERT
59# undef CRASSERT
60#endif
61#define CRASSERT Assert
62#endif
63/*#define IN_GUEST
64#if defined(IN_GUEST)
65#define VBOX_WITH_CRHGSMIPROFILE
66#endif */
67#ifdef VBOX_WITH_CRHGSMIPROFILE
68#include <iprt/time.h>
69#include <stdio.h>
70
71typedef struct VBOXCRHGSMIPROFILE
72{
73 uint64_t cStartTime;
74 uint64_t cStepsTime;
75 uint64_t cSteps;
76} VBOXCRHGSMIPROFILE, *PVBOXCRHGSMIPROFILE;
77
78#define VBOXCRHGSMIPROFILE_GET_TIME_NANO() RTTimeNanoTS()
79#define VBOXCRHGSMIPROFILE_GET_TIME_MILLI() RTTimeMilliTS()
80
81/* 10 sec */
82#define VBOXCRHGSMIPROFILE_LOG_STEP_TIME (10000000000.)
83
84DECLINLINE(void) vboxCrHgsmiProfileStart(PVBOXCRHGSMIPROFILE pProfile)
85{
86 pProfile->cStepsTime = 0;
87 pProfile->cSteps = 0;
88 pProfile->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
89}
90
91DECLINLINE(void) vboxCrHgsmiProfileStep(PVBOXCRHGSMIPROFILE pProfile, uint64_t cStepTime)
92{
93 pProfile->cStepsTime += cStepTime;
94 ++pProfile->cSteps;
95}
96
97typedef struct VBOXCRHGSMIPROFILE_SCOPE
98{
99 uint64_t cStartTime;
100/* bool bDisable;*/
101} VBOXCRHGSMIPROFILE_SCOPE, *PVBOXCRHGSMIPROFILE_SCOPE;
102
103static VBOXCRHGSMIPROFILE g_VBoxProfile;
104
105static void vboxCrHgsmiLog(char * szString, ...)
106{
107 char szBuffer[4096] = {0};
108 va_list pArgList;
109 va_start(pArgList, szString);
110 _vsnprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szString, pArgList);
111 va_end(pArgList);
112
113#ifdef VBOX_WITH_CRHGSMI
114 VBoxCrHgsmiLog(szBuffer);
115#else
116 OutputDebugString(szBuffer);
117#endif
118}
119
120DECLINLINE(void) vboxCrHgsmiProfileLog(PVBOXCRHGSMIPROFILE pProfile, uint64_t cTime)
121{
122 uint64_t profileTime = cTime - pProfile->cStartTime;
123 double percent = ((double)100.0) * pProfile->cStepsTime / profileTime;
124 double cps = ((double)1000000000.) * pProfile->cSteps / profileTime;
125 vboxCrHgsmiLog("hgcm: cps: %.1f, host %.1f%%\n", cps, percent);
126}
127
128DECLINLINE(void) vboxCrHgsmiProfileScopeEnter(PVBOXCRHGSMIPROFILE_SCOPE pScope)
129{
130/* pScope->bDisable = false; */
131 pScope->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
132}
133
134DECLINLINE(void) vboxCrHgsmiProfileScopeExit(PVBOXCRHGSMIPROFILE_SCOPE pScope)
135{
136/* if (!pScope->bDisable) */
137 {
138 uint64_t cTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
139 vboxCrHgsmiProfileStep(&g_VBoxProfile, cTime - pScope->cStartTime);
140 if (VBOXCRHGSMIPROFILE_LOG_STEP_TIME < cTime - g_VBoxProfile.cStartTime)
141 {
142 vboxCrHgsmiProfileLog(&g_VBoxProfile, cTime);
143 vboxCrHgsmiProfileStart(&g_VBoxProfile);
144 }
145 }
146}
147
148
149#define VBOXCRHGSMIPROFILE_INIT() vboxCrHgsmiProfileStart(&g_VBoxProfile)
150#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
151
152#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() \
153 VBOXCRHGSMIPROFILE_SCOPE __vboxCrHgsmiProfileScope; \
154 vboxCrHgsmiProfileScopeEnter(&__vboxCrHgsmiProfileScope);
155
156#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() \
157 vboxCrHgsmiProfileScopeExit(&__vboxCrHgsmiProfileScope); \
158
159
160#else
161#define VBOXCRHGSMIPROFILE_INIT() do {} while (0)
162#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
163#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() do {} while (0)
164#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() do {} while (0)
165#endif
166
167typedef struct {
168 int initialized;
169 int num_conns;
170 CRConnection **conns;
171 CRBufferPool *bufpool;
172#ifdef CHROMIUM_THREADSAFE
173 CRmutex mutex;
174 CRmutex recvmutex;
175#endif
176 CRNetReceiveFuncList *recv_list;
177 CRNetCloseFuncList *close_list;
178#ifdef RT_OS_WINDOWS
179 LPDIRECTDRAW pDirectDraw;
180#endif
181#ifdef IN_GUEST
182 uint32_t u32HostCaps;
183 bool fHostCapsInitialized;
184#endif
185#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
186 bool bHgsmiOn;
187#endif
188} CRVBOXHGCMDATA;
189
190static CRVBOXHGCMDATA g_crvboxhgcm = {0,};
191
192typedef enum {
193 CR_VBOXHGCM_USERALLOCATED,
194 CR_VBOXHGCM_MEMORY,
195 CR_VBOXHGCM_MEMORY_BIG
196#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
197 ,CR_VBOXHGCM_UHGSMI_BUFFER
198#endif
199} CRVBOXHGCMBUFFERKIND;
200
201#define CR_VBOXHGCM_BUFFER_MAGIC 0xABCDE321
202
203typedef struct CRVBOXHGCMBUFFER {
204 uint32_t magic;
205 CRVBOXHGCMBUFFERKIND kind;
206 union
207 {
208 struct
209 {
210 uint32_t len;
211 uint32_t allocated;
212 };
213
214#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
215 PVBOXUHGSMI_BUFFER pBuffer;
216#endif
217 };
218} CRVBOXHGCMBUFFER;
219
220#ifndef RT_OS_WINDOWS
221 #define TRUE true
222 #define FALSE false
223 #define INVALID_HANDLE_VALUE (-1)
224#endif
225
226
227#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
228
229/* add sizeof header + page align */
230#define CRVBOXHGSMI_PAGE_ALIGN(_s) (((_s) + 0xfff) & ~0xfff)
231#define CRVBOXHGSMI_BUF_HDR_SIZE() (sizeof (CRVBOXHGCMBUFFER))
232#define CRVBOXHGSMI_BUF_SIZE(_s) CRVBOXHGSMI_PAGE_ALIGN((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
233#define CRVBOXHGSMI_BUF_LOCK_SIZE(_s) ((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
234#define CRVBOXHGSMI_BUF_DATA(_p) ((void*)(((CRVBOXHGCMBUFFER*)(_p)) + 1))
235#define CRVBOXHGSMI_BUF_HDR(_p) (((CRVBOXHGCMBUFFER*)(_p)) - 1)
236#define CRVBOXHGSMI_BUF_OFFSET(_st2, _st1) ((uint32_t)(((uint8_t*)(_st2)) - ((uint8_t*)(_st1))))
237
238static int _crVBoxHGSMIClientInit(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI pHgsmi)
239{
240 int rc;
241 VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
242 pClient->pHgsmi = pHgsmi;
243 Flags.s.fCommand = 1;
244 rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1), Flags, &pClient->pCmdBuffer);
245 if (RT_SUCCESS(rc))
246 {
247 Flags.Value = 0;
248 rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1), Flags, &pClient->pHGBuffer);
249 if (RT_SUCCESS(rc))
250 {
251 pClient->pvHGBuffer = NULL;
252 pClient->bufpool = crBufferPoolInit(16);
253 return VINF_SUCCESS;
254 }
255 else
256 crWarning("_crVBoxHGSMIClientInit: pfnBufferCreate failed to allocate host->guest buffer");
257
258 pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
259 }
260 else
261 crWarning("_crVBoxHGSMIClientInit: pfnBufferCreate failed to allocate cmd buffer");
262
263 pClient->pHgsmi = NULL;
264 return rc;
265}
266
267void _crVBoxHGSMIBufferFree(void *data)
268{
269 PVBOXUHGSMI_BUFFER pBuffer = (PVBOXUHGSMI_BUFFER)data;
270 pBuffer->pfnDestroy(pBuffer);
271}
272
273static int _crVBoxHGSMIClientTerm(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI *ppHgsmi)
274{
275 if (pClient->bufpool)
276 crBufferPoolCallbackFree(pClient->bufpool, _crVBoxHGSMIBufferFree);
277 pClient->bufpool = NULL;
278
279 if (pClient->pHGBuffer)
280 {
281 pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
282 pClient->pHGBuffer = NULL;
283 }
284
285 if (pClient->pCmdBuffer)
286 {
287 pClient->pCmdBuffer->pfnDestroy(pClient->pCmdBuffer);
288 pClient->pCmdBuffer = NULL;
289 }
290
291 if (ppHgsmi)
292 {
293 *ppHgsmi = pClient->pHgsmi;
294 }
295 pClient->pHgsmi = NULL;
296
297 return VINF_SUCCESS;
298}
299
300
301#ifdef VBOX_CRHGSMI_WITH_D3DDEV
302
303static DECLCALLBACK(HVBOXCRHGSMI_CLIENT) _crVBoxHGSMIClientCreate(PVBOXUHGSMI pHgsmi)
304{
305 PCRVBOXHGSMI_CLIENT pClient = crAlloc(sizeof (CRVBOXHGSMI_CLIENT));
306
307 if (pClient)
308 {
309 int rc = _crVBoxHGSMIClientInit(pClient, pHgsmi);
310 if (RT_SUCCESS(rc))
311 return (HVBOXCRHGSMI_CLIENT)pClient;
312 else
313 crWarning("_crVBoxHGSMIClientCreate: _crVBoxHGSMIClientInit failed rc %d", rc);
314
315 crFree(pCLient);
316 }
317
318 return NULL;
319}
320
321static DECLCALLBACK(void) _crVBoxHGSMIClientDestroy(HVBOXCRHGSMI_CLIENT hClient)
322{
323 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)hClient;
324 _crVBoxHGSMIClientTerm(pClient, NULL);
325 crFree(pClient);
326}
327#endif
328
329DECLINLINE(PCRVBOXHGSMI_CLIENT) _crVBoxHGSMIClientGet(CRConnection *conn)
330{
331#ifdef VBOX_CRHGSMI_WITH_D3DDEV
332 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)VBoxCrHgsmiQueryClient();
333 CRASSERT(pClient);
334 return pClient;
335#else
336 if (conn->HgsmiClient.pHgsmi)
337 return &conn->HgsmiClient;
338 {
339 PVBOXUHGSMI pHgsmi = conn->pExternalHgsmi ? conn->pExternalHgsmi : VBoxCrHgsmiCreate();
340 if (pHgsmi)
341 {
342 int rc = _crVBoxHGSMIClientInit(&conn->HgsmiClient, pHgsmi);
343 if (RT_SUCCESS(rc))
344 {
345 CRASSERT(conn->HgsmiClient.pHgsmi);
346 return &conn->HgsmiClient;
347 }
348 else
349 crWarning("_crVBoxHGSMIClientGet: _crVBoxHGSMIClientInit failed rc %d", rc);
350 if (!conn->pExternalHgsmi)
351 VBoxCrHgsmiDestroy(pHgsmi);
352 }
353 else
354 {
355 crWarning("VBoxCrHgsmiCreate failed");
356 }
357 }
358 return NULL;
359#endif
360}
361
362static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
363{
364 PVBOXUHGSMI_BUFFER buf;
365 int rc;
366
367 buf = (PVBOXUHGSMI_BUFFER ) crBufferPoolPop(pClient->bufpool, cbSize);
368
369 if (!buf)
370 {
371 VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
372 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
373 (void *) pClient->bufpool,
374 cbSize);
375 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, cbSize, Flags, &buf);
376 if (RT_FAILURE(rc))
377 crWarning("_crVBoxHGSMIBufAlloc: Failed to Create a buffer of size(%d), rc(%d)\n", cbSize, rc);
378 }
379 return buf;
380}
381
382static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufFromHdr(CRVBOXHGCMBUFFER *pHdr)
383{
384 PVBOXUHGSMI_BUFFER pBuf;
385 int rc;
386 CRASSERT(pHdr->magic == CR_VBOXHGCM_BUFFER_MAGIC);
387 CRASSERT(pHdr->kind == CR_VBOXHGCM_UHGSMI_BUFFER);
388 pBuf = pHdr->pBuffer;
389 rc = pBuf->pfnUnlock(pBuf);
390 if (RT_FAILURE(rc))
391 {
392 crWarning("_crVBoxHGSMIBufFromHdr: pfnUnlock failed rc %d", rc);
393 return NULL;
394 }
395 return pBuf;
396}
397
398static void _crVBoxHGSMIBufFree(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf)
399{
400 crBufferPoolPush(pClient->bufpool, pBuf, pBuf->cbBuffer);
401}
402
403static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLock(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
404{
405 /* in theory it is OK to use one cmd buffer for asynch cmd submission
406 * because bDiscard flag should result in allocating a new memory backend if the
407 * allocation is still in use.
408 * However, NOTE: since one and the same semaphore synch event is used for completion notification,
409 * for the notification mechanism working as expected
410 * 1. host must complete commands in the same order as it receives them
411 * (to avoid situation when guest receives notification for another command completion)
412 * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
413 * 3. guest must wait for command completion in the same order as it submits them
414 * in case we can not satisfy any of the above, we should introduce multiple command buffers */
415 CRVBOXHGSMIHDR * pHdr;
416 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
417 int rc;
418 fFlags.Value = 0;
419 fFlags.s.fDiscard = 1;
420 rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
421 if (RT_SUCCESS(rc))
422 return pHdr;
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.s.fReadOnly = 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.s.fReadOnly = 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.s.fDoNotRetire = 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; /** @todo now rc == 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; /** @todo now rc == 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) /** @todo now rc == 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) /** @todo now rc == 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) /** @todo now rc == 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) /** @todo now rc == 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 /* Expect only CR_MESSAGE_OPCODES from the guest. */
1081 AssertPtrReturnVoid(conn->pBuffer);
1082
1083 if ( conn->cbBuffer >= sizeof(CRMessageHeader)
1084 && ((CRMessageHeader*) (conn->pBuffer))->type == CR_MESSAGE_OPCODES)
1085 {
1086 /* Looks good. */
1087 }
1088 else
1089 {
1090 AssertFailed();
1091 /** @todo Find out if this is the expected cleanup. */
1092 conn->cbBuffer = 0;
1093 conn->pBuffer = NULL;
1094 return;
1095 }
1096#endif
1097
1098#ifndef IN_GUEST
1099 if (conn->allow_redir_ptr)
1100 {
1101#endif
1102 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
1103
1104 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1105 hgcm_buffer->len = sizeof(CRMessageRedirPtr);
1106
1107 msg = (CRMessage *) (hgcm_buffer + 1);
1108
1109 msg->header.type = CR_MESSAGE_REDIR_PTR;
1110 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
1111 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
1112
1113#if defined(VBOX_WITH_CRHGSMI) && !defined(IN_GUEST)
1114 msg->redirptr.CmdData = conn->CmdData;
1115 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&msg->redirptr.CmdData);
1116 CRVBOXHGSMI_CMDDATA_CLEANUP(&conn->CmdData);
1117#endif
1118
1119 cached_type = msg->redirptr.pMessage->type;
1120
1121 conn->cbBuffer = 0;
1122 conn->pBuffer = NULL;
1123#ifndef IN_GUEST
1124 }
1125 else
1126 {
1127 /* we should NEVER have redir_ptr disabled with HGSMI command now */
1128 CRASSERT(!conn->CmdData.pvCmd);
1129 if ( len <= conn->buffer_size )
1130 {
1131 /* put in pre-allocated buffer */
1132 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1133 }
1134 else
1135 {
1136 /* allocate new buffer,
1137 * not using pool here as it's most likely one time transfer of huge texture
1138 */
1139 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
1140 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1141 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
1142 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
1143 }
1144
1145 hgcm_buffer->len = len;
1146 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
1147
1148 msg = (CRMessage *) (hgcm_buffer + 1);
1149 cached_type = msg->header.type;
1150 }
1151#endif /* !IN_GUEST*/
1152
1153 conn->recv_credits -= len;
1154 conn->total_bytes_recv += len;
1155 conn->recv_count++;
1156
1157 crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
1158
1159 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
1160 * OOB messages are the programmer's problem. -- Humper 12/17/01
1161 */
1162 if (cached_type != CR_MESSAGE_OPCODES
1163 && cached_type != CR_MESSAGE_OOB
1164 && cached_type != CR_MESSAGE_GATHER)
1165 {
1166 _crVBoxHGCMFree(conn, msg);
1167 }
1168}
1169
1170static void crVBoxHGCMReceiveMessage(CRConnection *conn)
1171{
1172 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1173#ifdef CHROMIUM_THREADSAFE
1174 crLockMutex(&g_crvboxhgcm.mutex);
1175#endif
1176 _crVBoxHGCMReceiveMessage(conn);
1177#ifdef CHROMIUM_THREADSAFE
1178 crUnlockMutex(&g_crvboxhgcm.mutex);
1179#endif
1180 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1181}
1182
1183
1184/*
1185 * Called on host side only, to "accept" client connection
1186 */
1187static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
1188{
1189 RT_NOREF(hostname, port);
1190 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1191 CRASSERT(conn && conn->pHostBuffer);
1192#ifdef IN_GUEST
1193 CRASSERT(FALSE);
1194#endif
1195 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1196}
1197
1198static int crVBoxHGCMSetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
1199{
1200 CRVBOXHGCMSETVERSION parms;
1201 int rc;
1202 RT_NOREF(vMajor, vMinor);
1203
1204 VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_VERSION, SHCRGL_CPARMS_SET_VERSION);
1205
1206 parms.vMajor.type = VMMDevHGCMParmType_32bit;
1207 parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
1208 parms.vMinor.type = VMMDevHGCMParmType_32bit;
1209 parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
1210
1211 rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
1212
1213 if (RT_SUCCESS(rc))
1214 {
1215 rc = parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
1216 if (RT_SUCCESS(rc))
1217 {
1218 conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
1219 conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
1220
1221 return VINF_SUCCESS;
1222 }
1223 else
1224 WARN(("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
1225 parms.vMajor.u.value32, parms.vMinor.u.value32));
1226 }
1227 else
1228 WARN(("crVBoxHGCMCall failed %d", rc));
1229
1230 return rc;
1231}
1232
1233static int crVBoxHGCMGetHostCapsLegacy(CRConnection *conn, uint32_t *pu32HostCaps)
1234{
1235 CRVBOXHGCMGETCAPS caps;
1236 int rc;
1237
1238 VBGL_HGCM_HDR_INIT(&caps.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_GET_CAPS_LEGACY, SHCRGL_CPARMS_GET_CAPS_LEGACY);
1239
1240 caps.Caps.type = VMMDevHGCMParmType_32bit;
1241 caps.Caps.u.value32 = 0;
1242
1243 rc = crVBoxHGCMCall(conn, &caps.hdr, sizeof(caps));
1244
1245 if (RT_SUCCESS(rc))
1246 {
1247 rc = caps.hdr.Hdr.rc;
1248 if (RT_SUCCESS(rc))
1249 {
1250 *pu32HostCaps = caps.Caps.u.value32;
1251 return VINF_SUCCESS;
1252 }
1253 else
1254 WARN(("SHCRGL_GUEST_FN_GET_CAPS failed %d", rc));
1255 return FALSE;
1256 }
1257 else
1258 WARN(("crVBoxHGCMCall failed %d", rc));
1259
1260 *pu32HostCaps = 0;
1261
1262 return rc;
1263}
1264
1265static int crVBoxHGCMSetPID(CRConnection *conn, unsigned long long pid)
1266{
1267 CRVBOXHGCMSETPID parms;
1268 int rc;
1269
1270 VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_PID, SHCRGL_CPARMS_SET_PID);
1271
1272 parms.u64PID.type = VMMDevHGCMParmType_64bit;
1273 parms.u64PID.u.value64 = pid;
1274
1275 rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
1276
1277 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
1278 {
1279 crWarning("SHCRGL_GUEST_FN_SET_PID failed!");
1280 return FALSE;
1281 }
1282
1283 return TRUE;
1284}
1285
1286/**
1287 * The function that actually connects. This should only be called by clients,
1288 * guests in vbox case.
1289 * Servers go through crVBoxHGCMAccept;
1290 */
1291static int crVBoxHGCMDoConnect( CRConnection *conn )
1292{
1293#ifdef IN_GUEST
1294 int rc;
1295 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1296 RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
1297 rc = VbglR3InitUser();
1298 if (RT_SUCCESS(rc))
1299 {
1300 uint32_t idClient;
1301 rc = VbglR3HGCMConnect("VBoxSharedCrOpenGL", &idClient);
1302 if (RT_SUCCESS(rc))
1303 {
1304 conn->u32ClientID = idClient;
1305 crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
1306
1307 rc = crVBoxHGCMSetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
1308 if (RT_FAILURE(rc))
1309 {
1310 WARN(("crVBoxHGCMSetVersion failed %d", rc));
1311 return FALSE;
1312 }
1313#ifdef RT_OS_WINDOWS
1314 rc = crVBoxHGCMSetPID(conn, GetCurrentProcessId());
1315#else
1316 rc = crVBoxHGCMSetPID(conn, crGetPID());
1317#endif
1318 if (RT_FAILURE(rc))
1319 {
1320 WARN(("crVBoxHGCMSetPID failed %Rrc", rc));
1321 return FALSE;
1322 }
1323
1324 if (!g_crvboxhgcm.fHostCapsInitialized)
1325 {
1326 rc = crVBoxHGCMGetHostCapsLegacy(conn, &g_crvboxhgcm.u32HostCaps);
1327 if (RT_FAILURE(rc))
1328 {
1329 WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %Rrc", rc));
1330 g_crvboxhgcm.u32HostCaps = 0;
1331 }
1332
1333 /* host may not support it, ignore any failures */
1334 g_crvboxhgcm.fHostCapsInitialized = true;
1335 }
1336
1337 if (g_crvboxhgcm.u32HostCaps & CR_VBOX_CAP_HOST_CAPS_NOT_SUFFICIENT)
1338 {
1339 crDebug("HGCM connect: insufficient host capabilities\n");
1340 g_crvboxhgcm.u32HostCaps = 0;
1341 return FALSE;
1342 }
1343
1344 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1345 return TRUE;
1346 }
1347
1348 crDebug("HGCM connect failed: %Rrc\n", rc);
1349 VbglR3Term();
1350 }
1351 else
1352 crDebug("Failed to initialize VbglR3 library: %Rrc\n", rc);
1353
1354 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1355 return FALSE;
1356
1357#else /* !IN_GUEST */
1358 crError("crVBoxHGCMDoConnect called on host side!");
1359 CRASSERT(FALSE);
1360 return FALSE;
1361#endif /* !IN_GUEST */
1362}
1363
1364static bool _crVBoxCommonDoDisconnectLocked( CRConnection *conn )
1365{
1366 int i;
1367 if (conn->pHostBuffer)
1368 {
1369 crFree(conn->pHostBuffer);
1370 conn->pHostBuffer = NULL;
1371 conn->cbHostBuffer = 0;
1372 conn->cbHostBufferAllocated = 0;
1373 }
1374
1375 conn->pBuffer = NULL;
1376 conn->cbBuffer = 0;
1377
1378 if (conn->type == CR_VBOXHGCM)
1379 {
1380 --g_crvboxhgcm.num_conns;
1381
1382 if (conn->index < g_crvboxhgcm.num_conns)
1383 {
1384 g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
1385 g_crvboxhgcm.conns[conn->index]->index = conn->index;
1386 }
1387 else g_crvboxhgcm.conns[conn->index] = NULL;
1388
1389 conn->type = CR_NO_CONNECTION;
1390 }
1391
1392 for (i = 0; i < g_crvboxhgcm.num_conns; i++)
1393 if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
1394 return true;
1395 return false;
1396}
1397
1398/** @todo same, replace DeviceIoControl with vbglR3DoIOCtl */
1399static void crVBoxHGCMDoDisconnect( CRConnection *conn )
1400{
1401 bool fHasActiveCons = false;
1402
1403 if (!g_crvboxhgcm.initialized) return;
1404
1405#ifdef CHROMIUM_THREADSAFE
1406 crLockMutex(&g_crvboxhgcm.mutex);
1407#endif
1408
1409 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1410
1411 fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
1412
1413#ifndef IN_GUEST
1414#else /* IN_GUEST */
1415 if (conn->u32ClientID)
1416 {
1417 int rc = VbglR3HGCMDisconnect(conn->u32ClientID);
1418 if (RT_FAILURE(rc))
1419 crDebug("Disconnect failed with %Rrc\n", rc);
1420 conn->u32ClientID = 0;
1421
1422 VbglR3Term();
1423 }
1424#endif /* IN_GUEST */
1425
1426 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1427
1428#ifdef CHROMIUM_THREADSAFE
1429 crUnlockMutex(&g_crvboxhgcm.mutex);
1430#endif
1431}
1432
1433static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
1434{
1435 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1436#ifdef CHROMIUM_THREADSAFE
1437 crLockMutex(&g_crvboxhgcm.mutex);
1438#endif
1439 _crVBoxHGCMFree(conn, mess);
1440 CRASSERT(FALSE);
1441#ifdef CHROMIUM_THREADSAFE
1442 crUnlockMutex(&g_crvboxhgcm.mutex);
1443#endif
1444 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1445}
1446
1447static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1448{
1449 RT_NOREF(conn, msg, len);
1450 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1451 CRASSERT(FALSE);
1452 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1453}
1454
1455#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1456
1457bool _crVBoxHGSMIInit()
1458{
1459#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1460 static
1461#endif
1462 int bHasHGSMI = -1;
1463
1464 if (bHasHGSMI < 0)
1465 {
1466 int rc;
1467 rc = VBoxCrHgsmiInit();
1468 if (RT_SUCCESS(rc))
1469 bHasHGSMI = 1;
1470 else
1471 bHasHGSMI = 0;
1472
1473 crDebug("CrHgsmi is %s", bHasHGSMI ? "ENABLED" : "DISABLED");
1474 }
1475
1476 CRASSERT(bHasHGSMI >= 0);
1477
1478 return bHasHGSMI;
1479}
1480
1481void _crVBoxHGSMITearDown()
1482{
1483 VBoxCrHgsmiTerm();
1484}
1485
1486static void *_crVBoxHGSMIDoAlloc(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1487{
1488 PVBOXUHGSMI_BUFFER buf;
1489 CRVBOXHGCMBUFFER *pData = NULL;
1490 uint32_t cbSize = conn->buffer_size;
1491 int rc;
1492
1493 buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
1494 if (buf)
1495 {
1496 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1497 buf->pvUserData = pClient;
1498 fFlags.Value = 0;
1499 fFlags.s.fDiscard = 1;
1500 rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
1501 if (RT_SUCCESS(rc))
1502 {
1503 pData->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1504 pData->kind = CR_VBOXHGCM_UHGSMI_BUFFER;
1505 pData->pBuffer = buf;
1506 }
1507 else
1508 {
1509 crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
1510 }
1511 return CRVBOXHGSMI_BUF_DATA(pData);
1512 }
1513 else
1514 {
1515 crWarning("_crVBoxHGSMIBufAlloc failed to allocate buffer of size (%d)", CRVBOXHGSMI_BUF_SIZE(cbSize));
1516 }
1517
1518 /* fall back */
1519 return _crVBoxHGCMAlloc(conn);
1520}
1521
1522static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
1523{
1524 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1525
1526 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1527
1528 if (hgcm_buffer->kind == CR_VBOXHGCM_UHGSMI_BUFFER)
1529 {
1530 PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1531 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1532 _crVBoxHGSMIBufFree(pClient, pBuf);
1533 }
1534 else
1535 {
1536 _crVBoxHGCMFree(conn, buf);
1537 }
1538}
1539
1540static void *crVBoxHGSMIAlloc(CRConnection *conn)
1541{
1542 PCRVBOXHGSMI_CLIENT pClient;
1543 void *pvBuf;
1544
1545 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1546
1547#ifdef CHROMIUM_THREADSAFE
1548 crLockMutex(&g_crvboxhgcm.mutex);
1549#endif
1550
1551 pClient = _crVBoxHGSMIClientGet(conn);
1552 if (pClient)
1553 {
1554 pvBuf = _crVBoxHGSMIDoAlloc(conn, pClient);
1555 CRASSERT(pvBuf);
1556 }
1557 else
1558 {
1559 pvBuf = _crVBoxHGCMAlloc(conn);
1560 }
1561
1562#ifdef CHROMIUM_THREADSAFE
1563 crUnlockMutex(&g_crvboxhgcm.mutex);
1564#endif
1565
1566 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1567
1568 return pvBuf;
1569}
1570
1571static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
1572{
1573 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1574#ifdef CHROMIUM_THREADSAFE
1575 crLockMutex(&g_crvboxhgcm.mutex);
1576#endif
1577 _crVBoxHGSMIFree(conn, buf);
1578#ifdef CHROMIUM_THREADSAFE
1579 crUnlockMutex(&g_crvboxhgcm.mutex);
1580#endif
1581 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1582}
1583
1584static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1585{
1586 CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1587 int rc;
1588 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1589 PVBOXUHGSMI_BUFFER pRecvBuffer;
1590 uint32_t cbBuffer;
1591
1592 CRASSERT(parms);
1593
1594 parms->hdr.result = VERR_WRONG_ORDER;
1595 parms->hdr.u32ClientID = conn->u32ClientID;
1596 parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
1597/* parms->hdr.u32Reserved = 0;*/
1598
1599 CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
1600 parms->iBuffer = 1;
1601 parms->cbBuffer = 0;
1602
1603 _crVBoxHGSMICmdBufferUnlock(pClient);
1604
1605 pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1606 CRASSERT(pRecvBuffer);
1607 if (!pRecvBuffer)
1608 return;
1609
1610 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1611
1612 aSubmit[1].pBuf = pRecvBuffer;
1613 aSubmit[1].offData = 0;
1614 aSubmit[1].cbData = pRecvBuffer->cbBuffer;
1615 aSubmit[1].fFlags.Value = 0;
1616 aSubmit[1].fFlags.s.fHostWriteOnly = 1;
1617
1618 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1619 if (RT_FAILURE(rc))
1620 {
1621 crError("pfnBufferSubmit failed with %d \n", rc);
1622 return;
1623 }
1624
1625 parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1626 CRASSERT(parms);
1627 if (!parms)
1628 {
1629 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1630 return;
1631 }
1632
1633 if (RT_SUCCESS(parms->hdr.result))
1634 cbBuffer = parms->cbBuffer;
1635 else
1636 cbBuffer = 0;
1637
1638 _crVBoxHGSMICmdBufferUnlock(pClient);
1639
1640 if (cbBuffer)
1641 {
1642 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
1643 CRASSERT(pvData);
1644 if (pvData)
1645 {
1646 conn->pBuffer = pvData;
1647 conn->cbBuffer = cbBuffer;
1648 }
1649 }
1650}
1651
1652static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1653{
1654 _crVBoxHGSMIPollHost(conn, pClient);
1655
1656 if (conn->cbBuffer)
1657 _crVBoxHGCMReceiveMessage(conn);
1658}
1659
1660/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
1661 * This halves the number of HGCM calls we do,
1662 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
1663 */
1664static void
1665_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
1666{
1667 CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1668 int rc;
1669 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
1670 PVBOXUHGSMI_BUFFER pBuf = NULL;
1671 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1672/* uint32_t cbBuffer;*/
1673
1674 parms->hdr.result = VERR_WRONG_ORDER;
1675 parms->hdr.u32ClientID = conn->u32ClientID;
1676 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
1677/* parms->hdr.u32Reserved = 0;*/
1678
1679 parms->iBuffer = 1;
1680
1681 CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
1682 parms->iWriteback = 2;
1683 parms->cbWriteback = 0;
1684
1685 _crVBoxHGSMICmdBufferUnlock(pClient);
1686
1687 if (!bIsBuffer)
1688 {
1689 void *pvBuf;
1690 pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
1691
1692 if (!pBuf)
1693 {
1694 /* fallback */
1695 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1696 return;
1697 }
1698
1699 CRASSERT(!offBuffer);
1700
1701 offBuffer = 0;
1702 fFlags.Value = 0;
1703 fFlags.s.fDiscard = 1;
1704 fFlags.s.fWriteOnly = 1;
1705 rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
1706 if (RT_SUCCESS(rc))
1707 {
1708 memcpy(pvBuf, buf, len);
1709 rc = pBuf->pfnUnlock(pBuf);
1710 CRASSERT(RT_SUCCESS(rc));
1711 }
1712 else
1713 {
1714 crWarning("_crVBoxHGSMIWriteReadExact: pfnUnlock failed rc %d", rc);
1715 _crVBoxHGSMIBufFree(pClient, pBuf);
1716 /* fallback */
1717 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1718 return;
1719 }
1720 }
1721 else
1722 {
1723 pBuf = (PVBOXUHGSMI_BUFFER)buf;
1724 }
1725
1726 do
1727 {
1728 PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1729 CRASSERT(pRecvBuffer);
1730 if (!pRecvBuffer)
1731 {
1732 break;
1733 }
1734
1735 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1736
1737 aSubmit[1].pBuf = pBuf;
1738 aSubmit[1].offData = offBuffer;
1739 aSubmit[1].cbData = len;
1740 aSubmit[1].fFlags.Value = 0;
1741 aSubmit[1].fFlags.s.fHostReadOnly = 1;
1742
1743 aSubmit[2].pBuf = pRecvBuffer;
1744 aSubmit[2].offData = 0;
1745 aSubmit[2].cbData = pRecvBuffer->cbBuffer;
1746 aSubmit[2].fFlags.Value = 0;
1747
1748 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 3);
1749 if (RT_FAILURE(rc))
1750 {
1751 crError("pfnBufferSubmit failed with %d \n", rc);
1752 break;
1753 }
1754
1755 parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1756 CRASSERT(parms);
1757 if (parms)
1758 {
1759 uint32_t cbWriteback = parms->cbWriteback;
1760 rc = parms->hdr.result;
1761#ifdef DEBUG_misha
1762 /* catch it here to test the buffer */
1763 Assert(RT_SUCCESS(parms->hdr.Hdr.rc) || parms->hdr.Hdr.rc == VERR_BUFFER_OVERFLOW);
1764#endif
1765 _crVBoxHGSMICmdBufferUnlock(pClient);
1766#ifdef DEBUG
1767 parms = NULL;
1768#endif
1769 if (RT_SUCCESS(rc))
1770 {
1771 if (cbWriteback)
1772 {
1773 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
1774 CRASSERT(pvData);
1775 if (pvData)
1776 {
1777 conn->pBuffer = pvData;
1778 conn->cbBuffer = cbWriteback;
1779 _crVBoxHGCMReceiveMessage(conn);
1780 }
1781 }
1782 }
1783 else if (VERR_BUFFER_OVERFLOW == rc)
1784 {
1785 VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
1786 PVBOXUHGSMI_BUFFER pNewBuf;
1787 CRASSERT(!pClient->pvHGBuffer);
1788 CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
1789 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
1790
1791 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pNewBuf);
1792 if (RT_SUCCESS(rc))
1793 {
1794 rc = pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
1795 CRASSERT(RT_SUCCESS(rc));
1796
1797 pClient->pHGBuffer = pNewBuf;
1798
1799 _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
1800 }
1801 else
1802 {
1803 crWarning("_crVBoxHGSMIWriteReadExact: pfnBufferCreate(%d) failed!", CRVBOXHGSMI_PAGE_ALIGN(cbWriteback));
1804 if (conn->cbHostBufferAllocated < cbWriteback)
1805 {
1806 crFree(conn->pHostBuffer);
1807 conn->cbHostBufferAllocated = cbWriteback;
1808 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
1809 }
1810 crVBoxHGCMReadExact(conn, NULL, cbWriteback);
1811 }
1812 }
1813 else
1814 {
1815 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
1816 }
1817 }
1818 else
1819 {
1820 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1821 break;
1822 }
1823 } while (0);
1824
1825 if (!bIsBuffer)
1826 _crVBoxHGSMIBufFree(pClient, pBuf);
1827
1828 return;
1829}
1830
1831static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
1832{
1833 int rc;
1834 int32_t callRes = VINF_SUCCESS; /* Shut up MSC. */
1835 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1836
1837#ifdef IN_GUEST
1838 if (conn->u32InjectClientID)
1839 {
1840 CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1841 CRASSERT(parms);
1842 if (!parms)
1843 {
1844 return;
1845 }
1846
1847 parms->hdr.result = VERR_WRONG_ORDER;
1848 parms->hdr.u32ClientID = conn->u32ClientID;
1849 parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
1850/* parms->hdr.u32Reserved = 0;*/
1851
1852 parms->u32ClientID = conn->u32InjectClientID;
1853
1854 parms->iBuffer = 1;
1855 _crVBoxHGSMICmdBufferUnlock(pClient);
1856
1857 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1858
1859 aSubmit[1].pBuf = pBuf;
1860 aSubmit[1].offData = offStart;
1861 aSubmit[1].cbData = len;
1862 aSubmit[1].fFlags.Value = 0;
1863 aSubmit[1].fFlags.s.fHostReadOnly = 1;
1864
1865 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1866 if (RT_SUCCESS(rc))
1867 {
1868 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1869 }
1870 else
1871 {
1872 /* we can not recover at this point, report error & exit */
1873 crError("pfnBufferSubmit failed with %d \n", rc);
1874 }
1875 }
1876 else
1877#endif
1878 {
1879 CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
1880
1881 parms->hdr.result = VERR_WRONG_ORDER;
1882 parms->hdr.u32ClientID = conn->u32ClientID;
1883 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
1884/* parms->hdr.u32Reserved = 0; */
1885
1886 parms->iBuffer = 1;
1887 _crVBoxHGSMICmdBufferUnlock(pClient);
1888
1889 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1890
1891 aSubmit[1].pBuf = pBuf;
1892 aSubmit[1].offData = offStart;
1893 aSubmit[1].cbData = len;
1894 aSubmit[1].fFlags.Value = 0;
1895 aSubmit[1].fFlags.s.fHostReadOnly = 1;
1896
1897 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1898 if (RT_SUCCESS(rc))
1899 {
1900 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1901 }
1902 else
1903 {
1904 /* we can not recover at this point, report error & exit */
1905 crError("Failed to submit CrHhgsmi buffer");
1906 }
1907 }
1908
1909 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
1910 {
1911 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
1912 }
1913}
1914
1915static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
1916 const void *start, unsigned int len)
1917{
1918 PCRVBOXHGSMI_CLIENT pClient;
1919 PVBOXUHGSMI_BUFFER pBuf;
1920 CRVBOXHGCMBUFFER *hgcm_buffer;
1921
1922 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1923
1924#ifdef CHROMIUM_THREADSAFE
1925 crLockMutex(&g_crvboxhgcm.mutex);
1926#endif
1927
1928 if (!bufp) /* We're sending a user-allocated buffer. */
1929 {
1930 pClient = _crVBoxHGSMIClientGet(conn);
1931 if (pClient)
1932 {
1933#ifndef IN_GUEST
1934 /** @todo remove temp buffer allocation in unpacker */
1935 /* we're at the host side, so just store data until guest polls us */
1936 _crVBoxHGCMWriteBytes(conn, start, len);
1937#else
1938 CRASSERT(!conn->u32InjectClientID);
1939 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
1940 _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
1941#endif
1942#ifdef CHROMIUM_THREADSAFE
1943 crUnlockMutex(&g_crvboxhgcm.mutex);
1944#endif
1945 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1946 return;
1947 }
1948
1949 /* fallback */
1950 crVBoxHGCMSend(conn, bufp, start, len);
1951#ifdef CHROMIUM_THREADSAFE
1952 crUnlockMutex(&g_crvboxhgcm.mutex);
1953#endif
1954 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1955 return;
1956 }
1957
1958 hgcm_buffer = (CRVBOXHGCMBUFFER *) *bufp - 1;
1959 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1960 if (hgcm_buffer->magic != CR_VBOXHGCM_BUFFER_MAGIC)
1961 {
1962 crError("HGCM buffer magic mismatch");
1963 }
1964
1965
1966 if (hgcm_buffer->kind != CR_VBOXHGCM_UHGSMI_BUFFER)
1967 {
1968 /* fallback */
1969 crVBoxHGCMSend(conn, bufp, start, len);
1970#ifdef CHROMIUM_THREADSAFE
1971 crUnlockMutex(&g_crvboxhgcm.mutex);
1972#endif
1973 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1974 return;
1975 }
1976
1977 /* The region [start .. start + len + 1] lies within a buffer that
1978 * was allocated with crVBoxHGCMAlloc() and can be put into the free
1979 * buffer pool when we're done sending it.
1980 */
1981
1982 pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1983 CRASSERT(pBuf);
1984 if (!pBuf)
1985 {
1986 crVBoxHGCMSend(conn, bufp, start, len);
1987#ifdef CHROMIUM_THREADSAFE
1988 crUnlockMutex(&g_crvboxhgcm.mutex);
1989#endif
1990 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1991 return;
1992 }
1993
1994 pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1995 if (pClient != &conn->HgsmiClient)
1996 {
1997 crError("HGSMI client mismatch");
1998 }
1999
2000 /* Length would be passed as part of HGCM pointer description
2001 * No need to prepend it to the buffer
2002 */
2003#ifdef IN_GUEST
2004 if (conn->u32InjectClientID)
2005 {
2006 _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
2007 }
2008 else
2009#endif
2010 {
2011 _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
2012 }
2013
2014 /* Reclaim this pointer for reuse */
2015 _crVBoxHGSMIBufFree(pClient, pBuf);
2016 /* Since the buffer's now in the 'free' buffer pool, the caller can't
2017 * use it any more. Setting bufp to NULL will make sure the caller
2018 * doesn't try to re-use the buffer.
2019 */
2020 *bufp = NULL;
2021
2022#ifdef CHROMIUM_THREADSAFE
2023 crUnlockMutex(&g_crvboxhgcm.mutex);
2024#endif
2025
2026 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2027}
2028
2029static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
2030{
2031 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2032
2033 CRASSERT(0);
2034
2035 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2036}
2037
2038static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
2039{
2040 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2041
2042 CRASSERT(0);
2043
2044 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2045}
2046
2047static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
2048{
2049 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2050
2051#ifdef CHROMIUM_THREADSAFE
2052 crLockMutex(&g_crvboxhgcm.mutex);
2053#endif
2054
2055 CRASSERT(0);
2056
2057 _crVBoxHGCMReceiveMessage(conn);
2058
2059#ifdef CHROMIUM_THREADSAFE
2060 crUnlockMutex(&g_crvboxhgcm.mutex);
2061#endif
2062
2063 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2064}
2065
2066/*
2067 * Called on host side only, to "accept" client connection
2068 */
2069static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
2070{
2071 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2072 CRASSERT(0);
2073
2074 CRASSERT(conn && conn->pHostBuffer);
2075#ifdef IN_GUEST
2076 CRASSERT(FALSE);
2077#endif
2078 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2079}
2080
2081static int crVBoxHGSMIDoConnect( CRConnection *conn )
2082{
2083 PCRVBOXHGSMI_CLIENT pClient;
2084 int rc = VINF_SUCCESS;
2085
2086#ifdef CHROMIUM_THREADSAFE
2087 crLockMutex(&g_crvboxhgcm.mutex);
2088#endif
2089
2090 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2091
2092 pClient = _crVBoxHGSMIClientGet(conn);
2093 if (pClient)
2094 {
2095 rc = VBoxCrHgsmiCtlConGetClientID(pClient->pHgsmi, &conn->u32ClientID);
2096 if (RT_FAILURE(rc))
2097 {
2098 WARN(("VBoxCrHgsmiCtlConGetClientID failed %d", rc));
2099 }
2100 if (!g_crvboxhgcm.fHostCapsInitialized)
2101 {
2102 rc = VBoxCrHgsmiCtlConGetHostCaps(pClient->pHgsmi, &g_crvboxhgcm.u32HostCaps);
2103 if (RT_SUCCESS(rc))
2104 {
2105 g_crvboxhgcm.fHostCapsInitialized = true;
2106 }
2107 else
2108 {
2109 WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %d", rc));
2110 g_crvboxhgcm.u32HostCaps = 0;
2111 }
2112 }
2113 }
2114 else
2115 {
2116 WARN(("_crVBoxHGSMIClientGet failed %d", rc));
2117 rc = VERR_GENERAL_FAILURE;
2118 }
2119
2120 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2121
2122#ifdef CHROMIUM_THREADSAFE
2123 crUnlockMutex(&g_crvboxhgcm.mutex);
2124#endif
2125 return RT_SUCCESS(rc);
2126}
2127
2128static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
2129{
2130 bool fHasActiveCons = false;
2131
2132 if (!g_crvboxhgcm.initialized) return;
2133
2134 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2135
2136#ifdef CHROMIUM_THREADSAFE
2137 crLockMutex(&g_crvboxhgcm.mutex);
2138#endif
2139
2140 fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
2141
2142#ifndef VBOX_CRHGSMI_WITH_D3DDEV
2143 if (conn->HgsmiClient.pHgsmi)
2144 {
2145 PVBOXUHGSMI pHgsmi;
2146 _crVBoxHGSMIClientTerm(&conn->HgsmiClient, &pHgsmi);
2147 CRASSERT(pHgsmi);
2148 if (!conn->pExternalHgsmi)
2149 VBoxCrHgsmiDestroy(pHgsmi);
2150 }
2151#else
2152# error "port me!"
2153#endif
2154
2155 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2156
2157#ifdef CHROMIUM_THREADSAFE
2158 crUnlockMutex(&g_crvboxhgcm.mutex);
2159#endif
2160}
2161
2162static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
2163{
2164 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2165#ifdef CHROMIUM_THREADSAFE
2166 crLockMutex(&g_crvboxhgcm.mutex);
2167#endif
2168 CRASSERT(0);
2169
2170 _crVBoxHGSMIFree(conn, mess);
2171
2172#ifdef CHROMIUM_THREADSAFE
2173 crUnlockMutex(&g_crvboxhgcm.mutex);
2174#endif
2175 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2176}
2177
2178static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
2179{
2180 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2181 CRASSERT(0);
2182
2183 CRASSERT(FALSE);
2184 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2185}
2186#endif
2187
2188void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
2189{
2190 (void) mtu;
2191
2192 g_crvboxhgcm.recv_list = rfl;
2193 g_crvboxhgcm.close_list = cfl;
2194 if (g_crvboxhgcm.initialized)
2195 {
2196 return;
2197 }
2198
2199 VBOXCRHGSMIPROFILE_INIT();
2200
2201 g_crvboxhgcm.initialized = 1;
2202
2203#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2204 g_crvboxhgcm.bHgsmiOn = _crVBoxHGSMIInit();
2205#endif
2206
2207 g_crvboxhgcm.num_conns = 0;
2208 g_crvboxhgcm.conns = NULL;
2209
2210 /* Can't open VBox guest driver here, because it gets called for host side as well */
2211 /** @todo as we have 2 dll versions, can do it now.*/
2212
2213#ifdef RT_OS_WINDOWS
2214 g_crvboxhgcm.pDirectDraw = NULL;
2215#endif
2216
2217#ifdef CHROMIUM_THREADSAFE
2218 crInitMutex(&g_crvboxhgcm.mutex);
2219 crInitMutex(&g_crvboxhgcm.recvmutex);
2220#endif
2221 g_crvboxhgcm.bufpool = crBufferPoolInit(16);
2222
2223#ifdef IN_GUEST
2224 g_crvboxhgcm.fHostCapsInitialized = false;
2225 g_crvboxhgcm.u32HostCaps = 0;
2226#endif
2227}
2228
2229/* Callback function used to free buffer pool entries */
2230static void crVBoxHGCMBufferFree(void *data)
2231{
2232 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
2233
2234 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2235
2236 switch (hgcm_buffer->kind)
2237 {
2238 case CR_VBOXHGCM_MEMORY:
2239 crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY: %p", hgcm_buffer);
2240 crFree( hgcm_buffer );
2241 break;
2242 case CR_VBOXHGCM_MEMORY_BIG:
2243 crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY_BIG: %p", hgcm_buffer);
2244 crFree( hgcm_buffer );
2245 break;
2246
2247 default:
2248 crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
2249 }
2250}
2251
2252void crVBoxHGCMTearDown(void)
2253{
2254 int32_t i, cCons;
2255
2256 if (!g_crvboxhgcm.initialized) return;
2257
2258#ifdef CHROMIUM_THREADSAFE
2259 crLockMutex(&g_crvboxhgcm.mutex);
2260#endif
2261
2262 /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
2263 * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
2264 * order of their connection.
2265 */
2266 cCons = g_crvboxhgcm.num_conns;
2267 for (i=0; i<cCons; i++)
2268 {
2269 /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
2270 crNetDisconnect(g_crvboxhgcm.conns[0]);
2271 }
2272 CRASSERT(0==g_crvboxhgcm.num_conns);
2273
2274 g_crvboxhgcm.initialized = 0;
2275
2276 if (g_crvboxhgcm.bufpool)
2277 crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
2278 g_crvboxhgcm.bufpool = NULL;
2279
2280#ifdef CHROMIUM_THREADSAFE
2281 crUnlockMutex(&g_crvboxhgcm.mutex);
2282 crFreeMutex(&g_crvboxhgcm.mutex);
2283 crFreeMutex(&g_crvboxhgcm.recvmutex);
2284#endif
2285
2286 crFree(g_crvboxhgcm.conns);
2287 g_crvboxhgcm.conns = NULL;
2288
2289#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2290 if (g_crvboxhgcm.bHgsmiOn)
2291 {
2292 _crVBoxHGSMITearDown();
2293 }
2294#endif
2295
2296#ifdef RT_OS_WINDOWS
2297 if (g_crvboxhgcm.pDirectDraw)
2298 {
2299 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
2300 g_crvboxhgcm.pDirectDraw = NULL;
2301 crDebug("DirectDraw released\n");
2302 }
2303#endif
2304}
2305
2306void crVBoxHGCMConnection(CRConnection *conn
2307#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2308 , struct VBOXUHGSMI *pHgsmi
2309#endif
2310 )
2311{
2312 int i, found = 0;
2313 int n_bytes;
2314
2315 CRASSERT(g_crvboxhgcm.initialized);
2316
2317#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2318 if (g_crvboxhgcm.bHgsmiOn)
2319 {
2320 conn->type = CR_VBOXHGCM;
2321 conn->Alloc = crVBoxHGSMIAlloc;
2322 conn->Send = crVBoxHGSMISend;
2323 conn->SendExact = crVBoxHGSMIWriteExact;
2324 conn->Recv = crVBoxHGSMISingleRecv;
2325 conn->RecvMsg = crVBoxHGSMIReceiveMessage;
2326 conn->Free = crVBoxHGSMIFree;
2327 conn->Accept = crVBoxHGSMIAccept;
2328 conn->Connect = crVBoxHGSMIDoConnect;
2329 conn->Disconnect = crVBoxHGSMIDoDisconnect;
2330 conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
2331 conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
2332 conn->pExternalHgsmi = pHgsmi;
2333 }
2334 else
2335#endif
2336 {
2337 conn->type = CR_VBOXHGCM;
2338 conn->Alloc = crVBoxHGCMAlloc;
2339 conn->Send = crVBoxHGCMSend;
2340 conn->SendExact = crVBoxHGCMWriteExact;
2341 conn->Recv = crVBoxHGCMSingleRecv;
2342 conn->RecvMsg = crVBoxHGCMReceiveMessage;
2343 conn->Free = crVBoxHGCMFree;
2344 conn->Accept = crVBoxHGCMAccept;
2345 conn->Connect = crVBoxHGCMDoConnect;
2346 conn->Disconnect = crVBoxHGCMDoDisconnect;
2347 conn->InstantReclaim = crVBoxHGCMInstantReclaim;
2348 conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
2349 }
2350 conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
2351 conn->actual_network = 1;
2352
2353 conn->krecv_buf_size = 0;
2354
2355 conn->pBuffer = NULL;
2356 conn->cbBuffer = 0;
2357 conn->allow_redir_ptr = 1;
2358
2359 /** @todo remove this crap at all later */
2360 conn->cbHostBufferAllocated = 2*1024;
2361 conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
2362 CRASSERT(conn->pHostBuffer);
2363 conn->cbHostBuffer = 0;
2364
2365#if !defined(IN_GUEST)
2366 RTListInit(&conn->PendingMsgList);
2367#endif
2368
2369#ifdef CHROMIUM_THREADSAFE
2370 crLockMutex(&g_crvboxhgcm.mutex);
2371#endif
2372 /* Find a free slot */
2373 for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
2374 if (g_crvboxhgcm.conns[i] == NULL) {
2375 conn->index = i;
2376 g_crvboxhgcm.conns[i] = conn;
2377 found = 1;
2378 break;
2379 }
2380 }
2381
2382 /* Realloc connection stack if we couldn't find a free slot */
2383 if (found == 0) {
2384 n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
2385 crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
2386 conn->index = g_crvboxhgcm.num_conns;
2387 g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
2388 }
2389#ifdef CHROMIUM_THREADSAFE
2390 crUnlockMutex(&g_crvboxhgcm.mutex);
2391#endif
2392}
2393
2394#if defined(IN_GUEST)
2395static void _crVBoxHGCMPerformPollHost(CRConnection *conn)
2396{
2397 if (conn->type == CR_NO_CONNECTION )
2398 return;
2399
2400 if (!conn->pBuffer)
2401 {
2402#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2403 PCRVBOXHGSMI_CLIENT pClient;
2404 if (g_crvboxhgcm.bHgsmiOn && !!(pClient = _crVBoxHGSMIClientGet(conn)))
2405 {
2406 _crVBoxHGSMIPollHost(conn, pClient);
2407 }
2408 else
2409#endif
2410 {
2411 crVBoxHGCMPollHost(conn);
2412 }
2413 }
2414}
2415#endif
2416
2417static void _crVBoxHGCMPerformReceiveMessage(CRConnection *conn)
2418{
2419 if ( conn->type == CR_NO_CONNECTION )
2420 return;
2421
2422 if (conn->cbBuffer>0)
2423 {
2424 _crVBoxHGCMReceiveMessage(conn);
2425 }
2426}
2427
2428#ifdef IN_GUEST
2429uint32_t crVBoxHGCMHostCapsGet(void)
2430{
2431 Assert(g_crvboxhgcm.fHostCapsInitialized);
2432 return g_crvboxhgcm.u32HostCaps;
2433}
2434#endif
2435
2436int crVBoxHGCMRecv(
2437#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2438 CRConnection *conn
2439#else
2440 void
2441#endif
2442 )
2443{
2444 int32_t i;
2445
2446 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2447
2448#ifdef CHROMIUM_THREADSAFE
2449 crLockMutex(&g_crvboxhgcm.mutex);
2450#endif
2451
2452#ifdef IN_GUEST
2453# if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2454 if (conn && g_crvboxhgcm.bHgsmiOn)
2455 {
2456 _crVBoxHGCMPerformPollHost(conn);
2457 _crVBoxHGCMPerformReceiveMessage(conn);
2458 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2459 return 0;
2460 }
2461# endif
2462 /* we're on guest side, poll host if it got something for us */
2463 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2464 {
2465 CRConnection *conn = g_crvboxhgcm.conns[i];
2466
2467 if ( !conn )
2468 continue;
2469
2470 _crVBoxHGCMPerformPollHost(conn);
2471 }
2472#endif
2473
2474 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2475 {
2476 CRConnection *conn = g_crvboxhgcm.conns[i];
2477
2478 if ( !conn )
2479 continue;
2480
2481 _crVBoxHGCMPerformReceiveMessage(conn);
2482 }
2483
2484#ifdef CHROMIUM_THREADSAFE
2485 crUnlockMutex(&g_crvboxhgcm.mutex);
2486#endif
2487
2488 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2489
2490 return 0;
2491}
2492
2493CRConnection** crVBoxHGCMDump( int *num )
2494{
2495 *num = g_crvboxhgcm.num_conns;
2496
2497 return g_crvboxhgcm.conns;
2498}
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