VirtualBox

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

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

crOpenGL/wddm: don't use VBoxGuest device to comply woth Metro apps security

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