VirtualBox

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

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

Additions/common/OpenGL: fix regressions from r117617/public r68472.
bugref:9060: vboxvideo: hanging login screen starting Ubuntu 17.10 guest with 3D
r117617/public r68472 and the follow-up switched from using duplicate code in
the X11 libGL code to access the guest driver and HGCM to using the common
code. It contained at least two problems: it failed to initialise the
runtime library before calling into the Guest library and it changed error
checking semantics slightly, causing us to fail to handle a too-small-buffer
error and sending GNOME Shell into an endless loop. This change fixes that
and also adds todo comments to other places where the error handling should
be cleaned up, but which I do not want to change and test just now.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use