VirtualBox

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

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

wddm/3d: merge chromium hgcm and hgsmi connection into one

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