VirtualBox

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

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

3D: texture unpacking reworked, bugref:9192. Merged r123597, r123598, r123600, r123601, r123755.

  • 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 73223 2018-07-18 20:07:50Z 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 /* Expect only CR_MESSAGE_OPCODES from the guest. */
1082 AssertPtrReturnVoid(conn->pBuffer);
1083
1084 if ( conn->cbBuffer >= sizeof(CRMessageHeader)
1085 && ((CRMessageHeader*) (conn->pBuffer))->type == CR_MESSAGE_OPCODES)
1086 {
1087 /* Looks good. */
1088 }
1089 else
1090 {
1091 AssertFailed();
1092 /** @todo Find out if this is the expected cleanup. */
1093 conn->cbBuffer = 0;
1094 conn->pBuffer = NULL;
1095 return;
1096 }
1097#endif
1098
1099#ifndef IN_GUEST
1100 if (conn->allow_redir_ptr)
1101 {
1102#endif
1103 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
1104
1105 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1106 hgcm_buffer->len = sizeof(CRMessageRedirPtr);
1107
1108 msg = (CRMessage *) (hgcm_buffer + 1);
1109
1110 msg->header.type = CR_MESSAGE_REDIR_PTR;
1111 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
1112 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
1113
1114#if defined(VBOX_WITH_CRHGSMI) && !defined(IN_GUEST)
1115 msg->redirptr.CmdData = conn->CmdData;
1116 CRVBOXHGSMI_CMDDATA_ASSERT_CONSISTENT(&msg->redirptr.CmdData);
1117 CRVBOXHGSMI_CMDDATA_CLEANUP(&conn->CmdData);
1118#endif
1119
1120 cached_type = msg->redirptr.pMessage->type;
1121
1122 conn->cbBuffer = 0;
1123 conn->pBuffer = NULL;
1124#ifndef IN_GUEST
1125 }
1126 else
1127 {
1128 /* we should NEVER have redir_ptr disabled with HGSMI command now */
1129 CRASSERT(!conn->CmdData.pvCmd);
1130 if ( len <= conn->buffer_size )
1131 {
1132 /* put in pre-allocated buffer */
1133 hgcm_buffer = (CRVBOXHGCMBUFFER *) _crVBoxHGCMAlloc( conn ) - 1;
1134 }
1135 else
1136 {
1137 /* allocate new buffer,
1138 * not using pool here as it's most likely one time transfer of huge texture
1139 */
1140 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
1141 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1142 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
1143 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
1144 }
1145
1146 hgcm_buffer->len = len;
1147 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
1148
1149 msg = (CRMessage *) (hgcm_buffer + 1);
1150 cached_type = msg->header.type;
1151 }
1152#endif /* !IN_GUEST*/
1153
1154 conn->recv_credits -= len;
1155 conn->total_bytes_recv += len;
1156 conn->recv_count++;
1157
1158 crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
1159
1160 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
1161 * OOB messages are the programmer's problem. -- Humper 12/17/01
1162 */
1163 if (cached_type != CR_MESSAGE_OPCODES
1164 && cached_type != CR_MESSAGE_OOB
1165 && cached_type != CR_MESSAGE_GATHER)
1166 {
1167 _crVBoxHGCMFree(conn, msg);
1168 }
1169}
1170
1171static void crVBoxHGCMReceiveMessage(CRConnection *conn)
1172{
1173 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1174#ifdef CHROMIUM_THREADSAFE
1175 crLockMutex(&g_crvboxhgcm.mutex);
1176#endif
1177 _crVBoxHGCMReceiveMessage(conn);
1178#ifdef CHROMIUM_THREADSAFE
1179 crUnlockMutex(&g_crvboxhgcm.mutex);
1180#endif
1181 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1182}
1183
1184
1185/*
1186 * Called on host side only, to "accept" client connection
1187 */
1188static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
1189{
1190 RT_NOREF(hostname, port);
1191 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1192 CRASSERT(conn && conn->pHostBuffer);
1193#ifdef IN_GUEST
1194 CRASSERT(FALSE);
1195#endif
1196 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1197}
1198
1199static int crVBoxHGCMSetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
1200{
1201 CRVBOXHGCMSETVERSION parms;
1202 int rc;
1203 RT_NOREF(vMajor, vMinor);
1204
1205 VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_VERSION, SHCRGL_CPARMS_SET_VERSION);
1206
1207 parms.vMajor.type = VMMDevHGCMParmType_32bit;
1208 parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
1209 parms.vMinor.type = VMMDevHGCMParmType_32bit;
1210 parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
1211
1212 rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
1213
1214 if (RT_SUCCESS(rc))
1215 {
1216 rc = parms.hdr.Hdr.rc; /** @todo now rc == parms.hdr.Hdr.rc */
1217 if (RT_SUCCESS(rc))
1218 {
1219 conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
1220 conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
1221
1222 return VINF_SUCCESS;
1223 }
1224 else
1225 WARN(("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
1226 parms.vMajor.u.value32, parms.vMinor.u.value32));
1227 }
1228 else
1229 WARN(("crVBoxHGCMCall failed %d", rc));
1230
1231 return rc;
1232}
1233
1234static int crVBoxHGCMGetHostCapsLegacy(CRConnection *conn, uint32_t *pu32HostCaps)
1235{
1236 CRVBOXHGCMGETCAPS caps;
1237 int rc;
1238
1239 VBGL_HGCM_HDR_INIT(&caps.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_GET_CAPS_LEGACY, SHCRGL_CPARMS_GET_CAPS_LEGACY);
1240
1241 caps.Caps.type = VMMDevHGCMParmType_32bit;
1242 caps.Caps.u.value32 = 0;
1243
1244 rc = crVBoxHGCMCall(conn, &caps.hdr, sizeof(caps));
1245
1246 if (RT_SUCCESS(rc))
1247 {
1248 rc = caps.hdr.Hdr.rc;
1249 if (RT_SUCCESS(rc))
1250 {
1251 *pu32HostCaps = caps.Caps.u.value32;
1252 return VINF_SUCCESS;
1253 }
1254 else
1255 WARN(("SHCRGL_GUEST_FN_GET_CAPS failed %d", rc));
1256 return FALSE;
1257 }
1258 else
1259 WARN(("crVBoxHGCMCall failed %d", rc));
1260
1261 *pu32HostCaps = 0;
1262
1263 return rc;
1264}
1265
1266static int crVBoxHGCMSetPID(CRConnection *conn, unsigned long long pid)
1267{
1268 CRVBOXHGCMSETPID parms;
1269 int rc;
1270
1271 VBGL_HGCM_HDR_INIT(&parms.hdr, conn->u32ClientID, SHCRGL_GUEST_FN_SET_PID, SHCRGL_CPARMS_SET_PID);
1272
1273 parms.u64PID.type = VMMDevHGCMParmType_64bit;
1274 parms.u64PID.u.value64 = pid;
1275
1276 rc = crVBoxHGCMCall(conn, &parms.hdr, sizeof(parms));
1277
1278 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.Hdr.rc) /** @todo now rc == parms.hdr.Hdr.rc */)
1279 {
1280 crWarning("SHCRGL_GUEST_FN_SET_PID failed!");
1281 return FALSE;
1282 }
1283
1284 return TRUE;
1285}
1286
1287/**
1288 * The function that actually connects. This should only be called by clients,
1289 * guests in vbox case.
1290 * Servers go through crVBoxHGCMAccept;
1291 */
1292static int crVBoxHGCMDoConnect( CRConnection *conn )
1293{
1294#ifdef IN_GUEST
1295 int rc;
1296 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1297 RTR3InitDll(RTR3INIT_FLAGS_UNOBTRUSIVE);
1298 rc = VbglR3InitUser();
1299 if (RT_SUCCESS(rc))
1300 {
1301 uint32_t idClient;
1302 rc = VbglR3HGCMConnect("VBoxSharedCrOpenGL", &idClient);
1303 if (RT_SUCCESS(rc))
1304 {
1305 conn->u32ClientID = idClient;
1306 crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
1307
1308 rc = crVBoxHGCMSetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
1309 if (RT_FAILURE(rc))
1310 {
1311 WARN(("crVBoxHGCMSetVersion failed %d", rc));
1312 return FALSE;
1313 }
1314#ifdef RT_OS_WINDOWS
1315 rc = crVBoxHGCMSetPID(conn, GetCurrentProcessId());
1316#else
1317 rc = crVBoxHGCMSetPID(conn, crGetPID());
1318#endif
1319 if (RT_FAILURE(rc))
1320 {
1321 WARN(("crVBoxHGCMSetPID failed %Rrc", rc));
1322 return FALSE;
1323 }
1324
1325 if (!g_crvboxhgcm.fHostCapsInitialized)
1326 {
1327 rc = crVBoxHGCMGetHostCapsLegacy(conn, &g_crvboxhgcm.u32HostCaps);
1328 if (RT_FAILURE(rc))
1329 {
1330 WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %Rrc", rc));
1331 g_crvboxhgcm.u32HostCaps = 0;
1332 }
1333
1334 /* host may not support it, ignore any failures */
1335 g_crvboxhgcm.fHostCapsInitialized = true;
1336 }
1337
1338 if (g_crvboxhgcm.u32HostCaps & CR_VBOX_CAP_HOST_CAPS_NOT_SUFFICIENT)
1339 {
1340 crDebug("HGCM connect: insufficient host capabilities\n");
1341 g_crvboxhgcm.u32HostCaps = 0;
1342 return FALSE;
1343 }
1344
1345 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1346 return TRUE;
1347 }
1348
1349 crDebug("HGCM connect failed: %Rrc\n", rc);
1350 VbglR3Term();
1351 }
1352 else
1353 crDebug("Failed to initialize VbglR3 library: %Rrc\n", rc);
1354
1355 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1356 return FALSE;
1357
1358#else /* !IN_GUEST */
1359 crError("crVBoxHGCMDoConnect called on host side!");
1360 CRASSERT(FALSE);
1361 return FALSE;
1362#endif /* !IN_GUEST */
1363}
1364
1365static bool _crVBoxCommonDoDisconnectLocked( CRConnection *conn )
1366{
1367 int i;
1368 if (conn->pHostBuffer)
1369 {
1370 crFree(conn->pHostBuffer);
1371 conn->pHostBuffer = NULL;
1372 conn->cbHostBuffer = 0;
1373 conn->cbHostBufferAllocated = 0;
1374 }
1375
1376 conn->pBuffer = NULL;
1377 conn->cbBuffer = 0;
1378
1379 if (conn->type == CR_VBOXHGCM)
1380 {
1381 --g_crvboxhgcm.num_conns;
1382
1383 if (conn->index < g_crvboxhgcm.num_conns)
1384 {
1385 g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
1386 g_crvboxhgcm.conns[conn->index]->index = conn->index;
1387 }
1388 else g_crvboxhgcm.conns[conn->index] = NULL;
1389
1390 conn->type = CR_NO_CONNECTION;
1391 }
1392
1393 for (i = 0; i < g_crvboxhgcm.num_conns; i++)
1394 if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
1395 return true;
1396 return false;
1397}
1398
1399/** @todo same, replace DeviceIoControl with vbglR3DoIOCtl */
1400static void crVBoxHGCMDoDisconnect( CRConnection *conn )
1401{
1402 bool fHasActiveCons = false;
1403
1404 if (!g_crvboxhgcm.initialized) return;
1405
1406#ifdef CHROMIUM_THREADSAFE
1407 crLockMutex(&g_crvboxhgcm.mutex);
1408#endif
1409
1410 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1411
1412 fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
1413
1414#ifndef IN_GUEST
1415#else /* IN_GUEST */
1416 if (conn->u32ClientID)
1417 {
1418 int rc = VbglR3HGCMDisconnect(conn->u32ClientID);
1419 if (RT_FAILURE(rc))
1420 crDebug("Disconnect failed with %Rrc\n", rc);
1421 conn->u32ClientID = 0;
1422
1423 VbglR3Term();
1424 }
1425#endif /* IN_GUEST */
1426
1427 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1428
1429#ifdef CHROMIUM_THREADSAFE
1430 crUnlockMutex(&g_crvboxhgcm.mutex);
1431#endif
1432}
1433
1434static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
1435{
1436 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1437#ifdef CHROMIUM_THREADSAFE
1438 crLockMutex(&g_crvboxhgcm.mutex);
1439#endif
1440 _crVBoxHGCMFree(conn, mess);
1441 CRASSERT(FALSE);
1442#ifdef CHROMIUM_THREADSAFE
1443 crUnlockMutex(&g_crvboxhgcm.mutex);
1444#endif
1445 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1446}
1447
1448static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1449{
1450 RT_NOREF(conn, msg, len);
1451 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1452 CRASSERT(FALSE);
1453 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1454}
1455
1456#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
1457
1458bool _crVBoxHGSMIInit()
1459{
1460#ifndef VBOX_CRHGSMI_WITH_D3DDEV
1461 static
1462#endif
1463 int bHasHGSMI = -1;
1464
1465 if (bHasHGSMI < 0)
1466 {
1467 int rc;
1468 rc = VBoxCrHgsmiInit();
1469 if (RT_SUCCESS(rc))
1470 bHasHGSMI = 1;
1471 else
1472 bHasHGSMI = 0;
1473
1474 crDebug("CrHgsmi is %s", bHasHGSMI ? "ENABLED" : "DISABLED");
1475 }
1476
1477 CRASSERT(bHasHGSMI >= 0);
1478
1479 return bHasHGSMI;
1480}
1481
1482void _crVBoxHGSMITearDown()
1483{
1484 VBoxCrHgsmiTerm();
1485}
1486
1487static void *_crVBoxHGSMIDoAlloc(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1488{
1489 PVBOXUHGSMI_BUFFER buf;
1490 CRVBOXHGCMBUFFER *pData = NULL;
1491 uint32_t cbSize = conn->buffer_size;
1492 int rc;
1493
1494 buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
1495 if (buf)
1496 {
1497 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1498 buf->pvUserData = pClient;
1499 fFlags.Value = 0;
1500 fFlags.bDiscard = 1;
1501 rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
1502 if (RT_SUCCESS(rc))
1503 {
1504 pData->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1505 pData->kind = CR_VBOXHGCM_UHGSMI_BUFFER;
1506 pData->pBuffer = buf;
1507 }
1508 else
1509 {
1510 crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
1511 }
1512 return CRVBOXHGSMI_BUF_DATA(pData);
1513 }
1514 else
1515 {
1516 crWarning("_crVBoxHGSMIBufAlloc failed to allocate buffer of size (%d)", CRVBOXHGSMI_BUF_SIZE(cbSize));
1517 }
1518
1519 /* fall back */
1520 return _crVBoxHGCMAlloc(conn);
1521}
1522
1523static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
1524{
1525 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
1526
1527 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1528
1529 if (hgcm_buffer->kind == CR_VBOXHGCM_UHGSMI_BUFFER)
1530 {
1531 PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1532 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1533 _crVBoxHGSMIBufFree(pClient, pBuf);
1534 }
1535 else
1536 {
1537 _crVBoxHGCMFree(conn, buf);
1538 }
1539}
1540
1541static void *crVBoxHGSMIAlloc(CRConnection *conn)
1542{
1543 PCRVBOXHGSMI_CLIENT pClient;
1544 void *pvBuf;
1545
1546 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1547
1548#ifdef CHROMIUM_THREADSAFE
1549 crLockMutex(&g_crvboxhgcm.mutex);
1550#endif
1551
1552 pClient = _crVBoxHGSMIClientGet(conn);
1553 if (pClient)
1554 {
1555 pvBuf = _crVBoxHGSMIDoAlloc(conn, pClient);
1556 CRASSERT(pvBuf);
1557 }
1558 else
1559 {
1560 pvBuf = _crVBoxHGCMAlloc(conn);
1561 }
1562
1563#ifdef CHROMIUM_THREADSAFE
1564 crUnlockMutex(&g_crvboxhgcm.mutex);
1565#endif
1566
1567 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1568
1569 return pvBuf;
1570}
1571
1572static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
1573{
1574 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1575#ifdef CHROMIUM_THREADSAFE
1576 crLockMutex(&g_crvboxhgcm.mutex);
1577#endif
1578 _crVBoxHGSMIFree(conn, buf);
1579#ifdef CHROMIUM_THREADSAFE
1580 crUnlockMutex(&g_crvboxhgcm.mutex);
1581#endif
1582 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1583}
1584
1585static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1586{
1587 CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1588 int rc;
1589 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1590 PVBOXUHGSMI_BUFFER pRecvBuffer;
1591 uint32_t cbBuffer;
1592
1593 CRASSERT(parms);
1594
1595 parms->hdr.result = VERR_WRONG_ORDER;
1596 parms->hdr.u32ClientID = conn->u32ClientID;
1597 parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
1598/* parms->hdr.u32Reserved = 0;*/
1599
1600 CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
1601 parms->iBuffer = 1;
1602 parms->cbBuffer = 0;
1603
1604 _crVBoxHGSMICmdBufferUnlock(pClient);
1605
1606 pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1607 CRASSERT(pRecvBuffer);
1608 if (!pRecvBuffer)
1609 return;
1610
1611 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1612
1613 aSubmit[1].pBuf = pRecvBuffer;
1614 aSubmit[1].offData = 0;
1615 aSubmit[1].cbData = pRecvBuffer->cbBuffer;
1616 aSubmit[1].fFlags.Value = 0;
1617 aSubmit[1].fFlags.bHostWriteOnly = 1;
1618
1619 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1620 if (RT_FAILURE(rc))
1621 {
1622 crError("pfnBufferSubmit failed with %d \n", rc);
1623 return;
1624 }
1625
1626 parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1627 CRASSERT(parms);
1628 if (!parms)
1629 {
1630 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1631 return;
1632 }
1633
1634 if (RT_SUCCESS(parms->hdr.result))
1635 cbBuffer = parms->cbBuffer;
1636 else
1637 cbBuffer = 0;
1638
1639 _crVBoxHGSMICmdBufferUnlock(pClient);
1640
1641 if (cbBuffer)
1642 {
1643 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
1644 CRASSERT(pvData);
1645 if (pvData)
1646 {
1647 conn->pBuffer = pvData;
1648 conn->cbBuffer = cbBuffer;
1649 }
1650 }
1651}
1652
1653static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1654{
1655 _crVBoxHGSMIPollHost(conn, pClient);
1656
1657 if (conn->cbBuffer)
1658 _crVBoxHGCMReceiveMessage(conn);
1659}
1660
1661/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
1662 * This halves the number of HGCM calls we do,
1663 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
1664 */
1665static void
1666_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
1667{
1668 CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1669 int rc;
1670 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
1671 PVBOXUHGSMI_BUFFER pBuf = NULL;
1672 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
1673/* uint32_t cbBuffer;*/
1674
1675 parms->hdr.result = VERR_WRONG_ORDER;
1676 parms->hdr.u32ClientID = conn->u32ClientID;
1677 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
1678/* parms->hdr.u32Reserved = 0;*/
1679
1680 parms->iBuffer = 1;
1681
1682 CRASSERT(!conn->pBuffer); /* make sure there's no data to process */
1683 parms->iWriteback = 2;
1684 parms->cbWriteback = 0;
1685
1686 _crVBoxHGSMICmdBufferUnlock(pClient);
1687
1688 if (!bIsBuffer)
1689 {
1690 void *pvBuf;
1691 pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
1692
1693 if (!pBuf)
1694 {
1695 /* fallback */
1696 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1697 return;
1698 }
1699
1700 CRASSERT(!offBuffer);
1701
1702 offBuffer = 0;
1703 fFlags.Value = 0;
1704 fFlags.bDiscard = 1;
1705 fFlags.bWriteOnly = 1;
1706 rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
1707 if (RT_SUCCESS(rc))
1708 {
1709 memcpy(pvBuf, buf, len);
1710 rc = pBuf->pfnUnlock(pBuf);
1711 CRASSERT(RT_SUCCESS(rc));
1712 }
1713 else
1714 {
1715 crWarning("_crVBoxHGSMIWriteReadExact: pfnUnlock failed rc %d", rc);
1716 _crVBoxHGSMIBufFree(pClient, pBuf);
1717 /* fallback */
1718 crVBoxHGCMWriteReadExact(conn, buf, len, CR_VBOXHGCM_USERALLOCATED);
1719 return;
1720 }
1721 }
1722 else
1723 {
1724 pBuf = (PVBOXUHGSMI_BUFFER)buf;
1725 }
1726
1727 do
1728 {
1729 PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
1730 CRASSERT(pRecvBuffer);
1731 if (!pRecvBuffer)
1732 {
1733 break;
1734 }
1735
1736 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1737
1738 aSubmit[1].pBuf = pBuf;
1739 aSubmit[1].offData = offBuffer;
1740 aSubmit[1].cbData = len;
1741 aSubmit[1].fFlags.Value = 0;
1742 aSubmit[1].fFlags.bHostReadOnly = 1;
1743
1744 aSubmit[2].pBuf = pRecvBuffer;
1745 aSubmit[2].offData = 0;
1746 aSubmit[2].cbData = pRecvBuffer->cbBuffer;
1747 aSubmit[2].fFlags.Value = 0;
1748
1749 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 3);
1750 if (RT_FAILURE(rc))
1751 {
1752 crError("pfnBufferSubmit failed with %d \n", rc);
1753 break;
1754 }
1755
1756 parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
1757 CRASSERT(parms);
1758 if (parms)
1759 {
1760 uint32_t cbWriteback = parms->cbWriteback;
1761 rc = parms->hdr.result;
1762#ifdef DEBUG_misha
1763 /* catch it here to test the buffer */
1764 Assert(RT_SUCCESS(parms->hdr.Hdr.rc) || parms->hdr.Hdr.rc == VERR_BUFFER_OVERFLOW);
1765#endif
1766 _crVBoxHGSMICmdBufferUnlock(pClient);
1767#ifdef DEBUG
1768 parms = NULL;
1769#endif
1770 if (RT_SUCCESS(rc))
1771 {
1772 if (cbWriteback)
1773 {
1774 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
1775 CRASSERT(pvData);
1776 if (pvData)
1777 {
1778 conn->pBuffer = pvData;
1779 conn->cbBuffer = cbWriteback;
1780 _crVBoxHGCMReceiveMessage(conn);
1781 }
1782 }
1783 }
1784 else if (VERR_BUFFER_OVERFLOW == rc)
1785 {
1786 VBOXUHGSMI_BUFFER_TYPE_FLAGS Flags = {0};
1787 PVBOXUHGSMI_BUFFER pNewBuf;
1788 CRASSERT(!pClient->pvHGBuffer);
1789 CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
1790 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
1791
1792 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback), Flags, &pNewBuf);
1793 if (RT_SUCCESS(rc))
1794 {
1795 rc = pClient->pHGBuffer->pfnDestroy(pClient->pHGBuffer);
1796 CRASSERT(RT_SUCCESS(rc));
1797
1798 pClient->pHGBuffer = pNewBuf;
1799
1800 _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
1801 }
1802 else
1803 {
1804 crWarning("_crVBoxHGSMIWriteReadExact: pfnBufferCreate(%d) failed!", CRVBOXHGSMI_PAGE_ALIGN(cbWriteback));
1805 if (conn->cbHostBufferAllocated < cbWriteback)
1806 {
1807 crFree(conn->pHostBuffer);
1808 conn->cbHostBufferAllocated = cbWriteback;
1809 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
1810 }
1811 crVBoxHGCMReadExact(conn, NULL, cbWriteback);
1812 }
1813 }
1814 else
1815 {
1816 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
1817 }
1818 }
1819 else
1820 {
1821 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
1822 break;
1823 }
1824 } while (0);
1825
1826 if (!bIsBuffer)
1827 _crVBoxHGSMIBufFree(pClient, pBuf);
1828
1829 return;
1830}
1831
1832static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
1833{
1834 int rc;
1835 int32_t callRes = VINF_SUCCESS; /* Shut up MSC. */
1836 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
1837
1838#ifdef IN_GUEST
1839 if (conn->u32InjectClientID)
1840 {
1841 CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
1842 CRASSERT(parms);
1843 if (!parms)
1844 {
1845 return;
1846 }
1847
1848 parms->hdr.result = VERR_WRONG_ORDER;
1849 parms->hdr.u32ClientID = conn->u32ClientID;
1850 parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
1851/* parms->hdr.u32Reserved = 0;*/
1852
1853 parms->u32ClientID = conn->u32InjectClientID;
1854
1855 parms->iBuffer = 1;
1856 _crVBoxHGSMICmdBufferUnlock(pClient);
1857
1858 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1859
1860 aSubmit[1].pBuf = pBuf;
1861 aSubmit[1].offData = offStart;
1862 aSubmit[1].cbData = len;
1863 aSubmit[1].fFlags.Value = 0;
1864 aSubmit[1].fFlags.bHostReadOnly = 1;
1865
1866 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1867 if (RT_SUCCESS(rc))
1868 {
1869 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1870 }
1871 else
1872 {
1873 /* we can not recover at this point, report error & exit */
1874 crError("pfnBufferSubmit failed with %d \n", rc);
1875 }
1876 }
1877 else
1878#endif
1879 {
1880 CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
1881
1882 parms->hdr.result = VERR_WRONG_ORDER;
1883 parms->hdr.u32ClientID = conn->u32ClientID;
1884 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
1885/* parms->hdr.u32Reserved = 0; */
1886
1887 parms->iBuffer = 1;
1888 _crVBoxHGSMICmdBufferUnlock(pClient);
1889
1890 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
1891
1892 aSubmit[1].pBuf = pBuf;
1893 aSubmit[1].offData = offStart;
1894 aSubmit[1].cbData = len;
1895 aSubmit[1].fFlags.Value = 0;
1896 aSubmit[1].fFlags.bHostReadOnly = 1;
1897
1898 rc = pClient->pHgsmi->pfnBufferSubmit(pClient->pHgsmi, aSubmit, 2);
1899 if (RT_SUCCESS(rc))
1900 {
1901 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
1902 }
1903 else
1904 {
1905 /* we can not recover at this point, report error & exit */
1906 crError("Failed to submit CrHhgsmi buffer");
1907 }
1908 }
1909
1910 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
1911 {
1912 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
1913 }
1914}
1915
1916static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
1917 const void *start, unsigned int len)
1918{
1919 PCRVBOXHGSMI_CLIENT pClient;
1920 PVBOXUHGSMI_BUFFER pBuf;
1921 CRVBOXHGCMBUFFER *hgcm_buffer;
1922
1923 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1924
1925#ifdef CHROMIUM_THREADSAFE
1926 crLockMutex(&g_crvboxhgcm.mutex);
1927#endif
1928
1929 if (!bufp) /* We're sending a user-allocated buffer. */
1930 {
1931 pClient = _crVBoxHGSMIClientGet(conn);
1932 if (pClient)
1933 {
1934#ifndef IN_GUEST
1935 /** @todo remove temp buffer allocation in unpacker */
1936 /* we're at the host side, so just store data until guest polls us */
1937 _crVBoxHGCMWriteBytes(conn, start, len);
1938#else
1939 CRASSERT(!conn->u32InjectClientID);
1940 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
1941 _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
1942#endif
1943#ifdef CHROMIUM_THREADSAFE
1944 crUnlockMutex(&g_crvboxhgcm.mutex);
1945#endif
1946 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1947 return;
1948 }
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 hgcm_buffer = (CRVBOXHGCMBUFFER *) *bufp - 1;
1960 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
1961 if (hgcm_buffer->magic != CR_VBOXHGCM_BUFFER_MAGIC)
1962 {
1963 crError("HGCM buffer magic mismatch");
1964 }
1965
1966
1967 if (hgcm_buffer->kind != CR_VBOXHGCM_UHGSMI_BUFFER)
1968 {
1969 /* fallback */
1970 crVBoxHGCMSend(conn, bufp, start, len);
1971#ifdef CHROMIUM_THREADSAFE
1972 crUnlockMutex(&g_crvboxhgcm.mutex);
1973#endif
1974 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1975 return;
1976 }
1977
1978 /* The region [start .. start + len + 1] lies within a buffer that
1979 * was allocated with crVBoxHGCMAlloc() and can be put into the free
1980 * buffer pool when we're done sending it.
1981 */
1982
1983 pBuf = _crVBoxHGSMIBufFromHdr(hgcm_buffer);
1984 CRASSERT(pBuf);
1985 if (!pBuf)
1986 {
1987 crVBoxHGCMSend(conn, bufp, start, len);
1988#ifdef CHROMIUM_THREADSAFE
1989 crUnlockMutex(&g_crvboxhgcm.mutex);
1990#endif
1991 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1992 return;
1993 }
1994
1995 pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1996 if (pClient != &conn->HgsmiClient)
1997 {
1998 crError("HGSMI client mismatch");
1999 }
2000
2001 /* Length would be passed as part of HGCM pointer description
2002 * No need to prepend it to the buffer
2003 */
2004#ifdef IN_GUEST
2005 if (conn->u32InjectClientID)
2006 {
2007 _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
2008 }
2009 else
2010#endif
2011 {
2012 _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
2013 }
2014
2015 /* Reclaim this pointer for reuse */
2016 _crVBoxHGSMIBufFree(pClient, pBuf);
2017 /* Since the buffer's now in the 'free' buffer pool, the caller can't
2018 * use it any more. Setting bufp to NULL will make sure the caller
2019 * doesn't try to re-use the buffer.
2020 */
2021 *bufp = NULL;
2022
2023#ifdef CHROMIUM_THREADSAFE
2024 crUnlockMutex(&g_crvboxhgcm.mutex);
2025#endif
2026
2027 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2028}
2029
2030static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
2031{
2032 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2033
2034 CRASSERT(0);
2035
2036 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2037}
2038
2039static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
2040{
2041 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2042
2043 CRASSERT(0);
2044
2045 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2046}
2047
2048static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
2049{
2050 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2051
2052#ifdef CHROMIUM_THREADSAFE
2053 crLockMutex(&g_crvboxhgcm.mutex);
2054#endif
2055
2056 CRASSERT(0);
2057
2058 _crVBoxHGCMReceiveMessage(conn);
2059
2060#ifdef CHROMIUM_THREADSAFE
2061 crUnlockMutex(&g_crvboxhgcm.mutex);
2062#endif
2063
2064 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2065}
2066
2067/*
2068 * Called on host side only, to "accept" client connection
2069 */
2070static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
2071{
2072 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2073 CRASSERT(0);
2074
2075 CRASSERT(conn && conn->pHostBuffer);
2076#ifdef IN_GUEST
2077 CRASSERT(FALSE);
2078#endif
2079 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2080}
2081
2082static int crVBoxHGSMIDoConnect( CRConnection *conn )
2083{
2084 PCRVBOXHGSMI_CLIENT pClient;
2085 int rc = VINF_SUCCESS;
2086
2087#ifdef CHROMIUM_THREADSAFE
2088 crLockMutex(&g_crvboxhgcm.mutex);
2089#endif
2090
2091 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2092
2093 pClient = _crVBoxHGSMIClientGet(conn);
2094 if (pClient)
2095 {
2096 rc = VBoxCrHgsmiCtlConGetClientID(pClient->pHgsmi, &conn->u32ClientID);
2097 if (RT_FAILURE(rc))
2098 {
2099 WARN(("VBoxCrHgsmiCtlConGetClientID failed %d", rc));
2100 }
2101 if (!g_crvboxhgcm.fHostCapsInitialized)
2102 {
2103 rc = VBoxCrHgsmiCtlConGetHostCaps(pClient->pHgsmi, &g_crvboxhgcm.u32HostCaps);
2104 if (RT_SUCCESS(rc))
2105 {
2106 g_crvboxhgcm.fHostCapsInitialized = true;
2107 }
2108 else
2109 {
2110 WARN(("VBoxCrHgsmiCtlConGetHostCaps failed %d", rc));
2111 g_crvboxhgcm.u32HostCaps = 0;
2112 }
2113 }
2114 }
2115 else
2116 {
2117 WARN(("_crVBoxHGSMIClientGet failed %d", rc));
2118 rc = VERR_GENERAL_FAILURE;
2119 }
2120
2121 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2122
2123#ifdef CHROMIUM_THREADSAFE
2124 crUnlockMutex(&g_crvboxhgcm.mutex);
2125#endif
2126 return RT_SUCCESS(rc);
2127}
2128
2129static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
2130{
2131 bool fHasActiveCons = false;
2132
2133 if (!g_crvboxhgcm.initialized) return;
2134
2135 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2136
2137#ifdef CHROMIUM_THREADSAFE
2138 crLockMutex(&g_crvboxhgcm.mutex);
2139#endif
2140
2141 fHasActiveCons = _crVBoxCommonDoDisconnectLocked(conn);
2142
2143#ifndef VBOX_CRHGSMI_WITH_D3DDEV
2144 if (conn->HgsmiClient.pHgsmi)
2145 {
2146 PVBOXUHGSMI pHgsmi;
2147 _crVBoxHGSMIClientTerm(&conn->HgsmiClient, &pHgsmi);
2148 CRASSERT(pHgsmi);
2149 if (!conn->pExternalHgsmi)
2150 VBoxCrHgsmiDestroy(pHgsmi);
2151 }
2152#else
2153# error "port me!"
2154#endif
2155
2156 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2157
2158#ifdef CHROMIUM_THREADSAFE
2159 crUnlockMutex(&g_crvboxhgcm.mutex);
2160#endif
2161}
2162
2163static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
2164{
2165 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2166#ifdef CHROMIUM_THREADSAFE
2167 crLockMutex(&g_crvboxhgcm.mutex);
2168#endif
2169 CRASSERT(0);
2170
2171 _crVBoxHGSMIFree(conn, mess);
2172
2173#ifdef CHROMIUM_THREADSAFE
2174 crUnlockMutex(&g_crvboxhgcm.mutex);
2175#endif
2176 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2177}
2178
2179static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
2180{
2181 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2182 CRASSERT(0);
2183
2184 CRASSERT(FALSE);
2185 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2186}
2187#endif
2188
2189void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
2190{
2191 (void) mtu;
2192
2193 g_crvboxhgcm.recv_list = rfl;
2194 g_crvboxhgcm.close_list = cfl;
2195 if (g_crvboxhgcm.initialized)
2196 {
2197 return;
2198 }
2199
2200 VBOXCRHGSMIPROFILE_INIT();
2201
2202 g_crvboxhgcm.initialized = 1;
2203
2204#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2205 g_crvboxhgcm.bHgsmiOn = _crVBoxHGSMIInit();
2206#endif
2207
2208 g_crvboxhgcm.num_conns = 0;
2209 g_crvboxhgcm.conns = NULL;
2210
2211 /* Can't open VBox guest driver here, because it gets called for host side as well */
2212 /** @todo as we have 2 dll versions, can do it now.*/
2213
2214#ifdef RT_OS_WINDOWS
2215 g_crvboxhgcm.pDirectDraw = NULL;
2216#endif
2217
2218#ifdef CHROMIUM_THREADSAFE
2219 crInitMutex(&g_crvboxhgcm.mutex);
2220 crInitMutex(&g_crvboxhgcm.recvmutex);
2221#endif
2222 g_crvboxhgcm.bufpool = crBufferPoolInit(16);
2223
2224#ifdef IN_GUEST
2225 g_crvboxhgcm.fHostCapsInitialized = false;
2226 g_crvboxhgcm.u32HostCaps = 0;
2227#endif
2228}
2229
2230/* Callback function used to free buffer pool entries */
2231static void crVBoxHGCMBufferFree(void *data)
2232{
2233 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
2234
2235 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
2236
2237 switch (hgcm_buffer->kind)
2238 {
2239 case CR_VBOXHGCM_MEMORY:
2240 crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY: %p", hgcm_buffer);
2241 crFree( hgcm_buffer );
2242 break;
2243 case CR_VBOXHGCM_MEMORY_BIG:
2244 crDebug("crVBoxHGCMBufferFree: CR_VBOXHGCM_MEMORY_BIG: %p", hgcm_buffer);
2245 crFree( hgcm_buffer );
2246 break;
2247
2248 default:
2249 crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
2250 }
2251}
2252
2253void crVBoxHGCMTearDown(void)
2254{
2255 int32_t i, cCons;
2256
2257 if (!g_crvboxhgcm.initialized) return;
2258
2259#ifdef CHROMIUM_THREADSAFE
2260 crLockMutex(&g_crvboxhgcm.mutex);
2261#endif
2262
2263 /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
2264 * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
2265 * order of their connection.
2266 */
2267 cCons = g_crvboxhgcm.num_conns;
2268 for (i=0; i<cCons; i++)
2269 {
2270 /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
2271 crNetDisconnect(g_crvboxhgcm.conns[0]);
2272 }
2273 CRASSERT(0==g_crvboxhgcm.num_conns);
2274
2275 g_crvboxhgcm.initialized = 0;
2276
2277 if (g_crvboxhgcm.bufpool)
2278 crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
2279 g_crvboxhgcm.bufpool = NULL;
2280
2281#ifdef CHROMIUM_THREADSAFE
2282 crUnlockMutex(&g_crvboxhgcm.mutex);
2283 crFreeMutex(&g_crvboxhgcm.mutex);
2284 crFreeMutex(&g_crvboxhgcm.recvmutex);
2285#endif
2286
2287 crFree(g_crvboxhgcm.conns);
2288 g_crvboxhgcm.conns = NULL;
2289
2290#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2291 if (g_crvboxhgcm.bHgsmiOn)
2292 {
2293 _crVBoxHGSMITearDown();
2294 }
2295#endif
2296
2297#ifdef RT_OS_WINDOWS
2298 if (g_crvboxhgcm.pDirectDraw)
2299 {
2300 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
2301 g_crvboxhgcm.pDirectDraw = NULL;
2302 crDebug("DirectDraw released\n");
2303 }
2304#endif
2305}
2306
2307void crVBoxHGCMConnection(CRConnection *conn
2308#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2309 , struct VBOXUHGSMI *pHgsmi
2310#endif
2311 )
2312{
2313 int i, found = 0;
2314 int n_bytes;
2315
2316 CRASSERT(g_crvboxhgcm.initialized);
2317
2318#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2319 if (g_crvboxhgcm.bHgsmiOn)
2320 {
2321 conn->type = CR_VBOXHGCM;
2322 conn->Alloc = crVBoxHGSMIAlloc;
2323 conn->Send = crVBoxHGSMISend;
2324 conn->SendExact = crVBoxHGSMIWriteExact;
2325 conn->Recv = crVBoxHGSMISingleRecv;
2326 conn->RecvMsg = crVBoxHGSMIReceiveMessage;
2327 conn->Free = crVBoxHGSMIFree;
2328 conn->Accept = crVBoxHGSMIAccept;
2329 conn->Connect = crVBoxHGSMIDoConnect;
2330 conn->Disconnect = crVBoxHGSMIDoDisconnect;
2331 conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
2332 conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
2333 conn->pExternalHgsmi = pHgsmi;
2334 }
2335 else
2336#endif
2337 {
2338 conn->type = CR_VBOXHGCM;
2339 conn->Alloc = crVBoxHGCMAlloc;
2340 conn->Send = crVBoxHGCMSend;
2341 conn->SendExact = crVBoxHGCMWriteExact;
2342 conn->Recv = crVBoxHGCMSingleRecv;
2343 conn->RecvMsg = crVBoxHGCMReceiveMessage;
2344 conn->Free = crVBoxHGCMFree;
2345 conn->Accept = crVBoxHGCMAccept;
2346 conn->Connect = crVBoxHGCMDoConnect;
2347 conn->Disconnect = crVBoxHGCMDoDisconnect;
2348 conn->InstantReclaim = crVBoxHGCMInstantReclaim;
2349 conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
2350 }
2351 conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
2352 conn->actual_network = 1;
2353
2354 conn->krecv_buf_size = 0;
2355
2356 conn->pBuffer = NULL;
2357 conn->cbBuffer = 0;
2358 conn->allow_redir_ptr = 1;
2359
2360 /** @todo remove this crap at all later */
2361 conn->cbHostBufferAllocated = 2*1024;
2362 conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
2363 CRASSERT(conn->pHostBuffer);
2364 conn->cbHostBuffer = 0;
2365
2366#if !defined(IN_GUEST)
2367 RTListInit(&conn->PendingMsgList);
2368#endif
2369
2370#ifdef CHROMIUM_THREADSAFE
2371 crLockMutex(&g_crvboxhgcm.mutex);
2372#endif
2373 /* Find a free slot */
2374 for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
2375 if (g_crvboxhgcm.conns[i] == NULL) {
2376 conn->index = i;
2377 g_crvboxhgcm.conns[i] = conn;
2378 found = 1;
2379 break;
2380 }
2381 }
2382
2383 /* Realloc connection stack if we couldn't find a free slot */
2384 if (found == 0) {
2385 n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
2386 crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
2387 conn->index = g_crvboxhgcm.num_conns;
2388 g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
2389 }
2390#ifdef CHROMIUM_THREADSAFE
2391 crUnlockMutex(&g_crvboxhgcm.mutex);
2392#endif
2393}
2394
2395#if defined(IN_GUEST)
2396static void _crVBoxHGCMPerformPollHost(CRConnection *conn)
2397{
2398 if (conn->type == CR_NO_CONNECTION )
2399 return;
2400
2401 if (!conn->pBuffer)
2402 {
2403#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2404 PCRVBOXHGSMI_CLIENT pClient;
2405 if (g_crvboxhgcm.bHgsmiOn && !!(pClient = _crVBoxHGSMIClientGet(conn)))
2406 {
2407 _crVBoxHGSMIPollHost(conn, pClient);
2408 }
2409 else
2410#endif
2411 {
2412 crVBoxHGCMPollHost(conn);
2413 }
2414 }
2415}
2416#endif
2417
2418static void _crVBoxHGCMPerformReceiveMessage(CRConnection *conn)
2419{
2420 if ( conn->type == CR_NO_CONNECTION )
2421 return;
2422
2423 if (conn->cbBuffer>0)
2424 {
2425 _crVBoxHGCMReceiveMessage(conn);
2426 }
2427}
2428
2429#ifdef IN_GUEST
2430uint32_t crVBoxHGCMHostCapsGet(void)
2431{
2432 Assert(g_crvboxhgcm.fHostCapsInitialized);
2433 return g_crvboxhgcm.u32HostCaps;
2434}
2435#endif
2436
2437int crVBoxHGCMRecv(
2438#if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2439 CRConnection *conn
2440#else
2441 void
2442#endif
2443 )
2444{
2445 int32_t i;
2446
2447 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
2448
2449#ifdef CHROMIUM_THREADSAFE
2450 crLockMutex(&g_crvboxhgcm.mutex);
2451#endif
2452
2453#ifdef IN_GUEST
2454# if defined(VBOX_WITH_CRHGSMI) && defined(IN_GUEST)
2455 if (conn && g_crvboxhgcm.bHgsmiOn)
2456 {
2457 _crVBoxHGCMPerformPollHost(conn);
2458 _crVBoxHGCMPerformReceiveMessage(conn);
2459 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2460 return 0;
2461 }
2462# endif
2463 /* we're on guest side, poll host if it got something for us */
2464 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2465 {
2466 CRConnection *conn = g_crvboxhgcm.conns[i];
2467
2468 if ( !conn )
2469 continue;
2470
2471 _crVBoxHGCMPerformPollHost(conn);
2472 }
2473#endif
2474
2475 for (i=0; i<g_crvboxhgcm.num_conns; i++)
2476 {
2477 CRConnection *conn = g_crvboxhgcm.conns[i];
2478
2479 if ( !conn )
2480 continue;
2481
2482 _crVBoxHGCMPerformReceiveMessage(conn);
2483 }
2484
2485#ifdef CHROMIUM_THREADSAFE
2486 crUnlockMutex(&g_crvboxhgcm.mutex);
2487#endif
2488
2489 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
2490
2491 return 0;
2492}
2493
2494CRConnection** crVBoxHGCMDump( int *num )
2495{
2496 *num = g_crvboxhgcm.num_conns;
2497
2498 return g_crvboxhgcm.conns;
2499}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use