VirtualBox

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

Last change on this file since 44528 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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