VirtualBox

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

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

crOpenGL: don't try hgsmi when unavailable

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

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