VirtualBox

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

Last change on this file since 41058 was 41058, checked in by vboxsync, 13 years ago

crHgsmi cleanup & adjustments

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette