VirtualBox

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

Last change on this file since 76376 was 76376, checked in by vboxsync, 5 years ago

VBoxUhgsmi.h: GCC doesn't like unnamed sub-structures in C++ code, so ditched them for VBOXUHGSMI_BUFFER_TYPE_FLAGS, VBOXUHGSMI_BUFFER_LOCK_FLAGS and VBOXUHGSMI_BUFFER_SUBMIT_FLAGS. Also skipped the outer wrapper structures for each of these types as all it contained was an unnamed union, so just make the typedefs unions straight away. Fixed some hungarian inconsistency between the three types ('b' == byte, not boolean in VBox, don't forget).

  • 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 76376 2018-12-22 22:32:24Z 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.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.bDiscard = 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.

© 2023 Oracle
ContactPrivacy policyTerms of Use