VirtualBox

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

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

crOpenGL: proper handling disabled 3D case for HGSMI

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