VirtualBox

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

Last change on this file since 33684 was 33684, checked in by vboxsync, 14 years ago

wddm/3d: fix hgcm fallback (for insufficient hgsmi resources)

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