VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/vboxhgsmi.c@ 42499

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

crOpenGL: fix not disappearing windows on non wddm/aero

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.2 KB
Line 
1/* $Id: vboxhgsmi.c 34110 2010-11-16 12:10:23Z 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//#define IN_GUEST
19#ifdef IN_GUEST
20#ifdef RT_OS_WINDOWS
21 #include <windows.h>
22 #include <ddraw.h>
23#else
24 #include <sys/ioctl.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <unistd.h>
29#endif
30
31#include "cr_error.h"
32#include "cr_net.h"
33#include "cr_bufpool.h"
34#include "cr_mem.h"
35#include "cr_string.h"
36#include "cr_endian.h"
37#include "cr_threads.h"
38#include "net_internals.h"
39#include "cr_process.h"
40
41#include <iprt/thread.h>
42#include <iprt/assert.h>
43
44#include <VBox/VBoxCrHgsmi.h>
45#if 1 /** @todo Try use the Vbgl interface instead of talking directly to the driver? */
46# include <VBox/VBoxGuest.h>
47#else
48# include <VBox/VBoxGuestLib.h>
49#endif
50#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
51
52#ifndef IN_GUEST
53# error "Hgsmi is supported for guest lib only!!"
54#endif
55
56#ifdef DEBUG_misha
57# ifdef CRASSERT
58# undef CRASSERT
59# endif
60# define CRASSERT Assert
61#endif
62
63#define VBOX_WITH_CRHGSMIPROFILE
64#ifdef VBOX_WITH_CRHGSMIPROFILE
65#include <iprt/time.h>
66#include <stdio.h>
67
68typedef struct VBOXCRHGSMIPROFILE
69{
70 uint64_t cStartTime;
71 uint64_t cStepsTime;
72 uint64_t cSteps;
73} VBOXCRHGSMIPROFILE, *PVBOXCRHGSMIPROFILE;
74
75#define VBOXCRHGSMIPROFILE_GET_TIME_NANO() RTTimeNanoTS()
76#define VBOXCRHGSMIPROFILE_GET_TIME_MILLI() RTTimeMilliTS()
77
78/* 10 sec */
79#define VBOXCRHGSMIPROFILE_LOG_STEP_TIME (10000000000.)
80
81DECLINLINE(void) vboxCrHgsmiProfileStart(PVBOXCRHGSMIPROFILE pProfile)
82{
83 pProfile->cStepsTime = 0;
84 pProfile->cSteps = 0;
85 pProfile->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
86}
87
88DECLINLINE(void) vboxCrHgsmiProfileStep(PVBOXCRHGSMIPROFILE pProfile, uint64_t cStepTime)
89{
90 pProfile->cStepsTime += cStepTime;
91 ++pProfile->cSteps;
92}
93
94typedef struct VBOXCRHGSMIPROFILE_SCOPE
95{
96 uint64_t cStartTime;
97// bool bDisable;
98} VBOXCRHGSMIPROFILE_SCOPE, *PVBOXCRHGSMIPROFILE_SCOPE;
99
100static VBOXCRHGSMIPROFILE g_VBoxProfile;
101
102static void vboxCrHgsmiLog(char * szString, ...)
103{
104 char szBuffer[4096] = {0};
105 va_list pArgList;
106 va_start(pArgList, szString);
107 _vsnprintf(szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]), szString, pArgList);
108 va_end(pArgList);
109
110 VBoxCrHgsmiLog(szBuffer);
111}
112
113DECLINLINE(void) vboxCrHgsmiProfileLog(PVBOXCRHGSMIPROFILE pProfile, uint64_t cTime)
114{
115 uint64_t profileTime = cTime - pProfile->cStartTime;
116 double percent = ((double)100.0) * pProfile->cStepsTime / profileTime;
117 double cps = ((double)1000000000.) * pProfile->cSteps / profileTime;
118 vboxCrHgsmiLog("hgsmi: cps: %.1f, host %.1f%%\n", cps, percent);
119}
120
121DECLINLINE(void) vboxCrHgsmiProfileScopeEnter(PVBOXCRHGSMIPROFILE_SCOPE pScope)
122{
123// pScope->bDisable = false;
124 pScope->cStartTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
125}
126
127DECLINLINE(void) vboxCrHgsmiProfileScopeExit(PVBOXCRHGSMIPROFILE_SCOPE pScope)
128{
129// if (!pScope->bDisable)
130 {
131 uint64_t cTime = VBOXCRHGSMIPROFILE_GET_TIME_NANO();
132 vboxCrHgsmiProfileStep(&g_VBoxProfile, cTime - pScope->cStartTime);
133 if (VBOXCRHGSMIPROFILE_LOG_STEP_TIME < cTime - g_VBoxProfile.cStartTime)
134 {
135 vboxCrHgsmiProfileLog(&g_VBoxProfile, cTime);
136 vboxCrHgsmiProfileStart(&g_VBoxProfile);
137 }
138 }
139}
140
141
142#define VBOXCRHGSMIPROFILE_INIT() vboxCrHgsmiProfileStart(&g_VBoxProfile)
143#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
144
145#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() \
146 VBOXCRHGSMIPROFILE_SCOPE __vboxCrHgsmiProfileScope; \
147 vboxCrHgsmiProfileScopeEnter(&__vboxCrHgsmiProfileScope);
148
149#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() \
150 vboxCrHgsmiProfileScopeExit(&__vboxCrHgsmiProfileScope); \
151
152
153#else
154#define VBOXCRHGSMIPROFILE_INIT() do {} while (0)
155#define VBOXCRHGSMIPROFILE_TERM() do {} while (0)
156#define VBOXCRHGSMIPROFILE_FUNC_PROLOGUE() do {} while (0)
157#define VBOXCRHGSMIPROFILE_FUNC_EPILOGUE() do {} while (0)
158#endif
159
160
161typedef struct {
162 int initialized;
163 int num_conns;
164 CRConnection **conns;
165#ifdef CHROMIUM_THREADSAFE
166 CRmutex mutex;
167 CRmutex recvmutex;
168#endif
169 CRNetReceiveFuncList *recv_list;
170 CRNetCloseFuncList *close_list;
171 CRBufferPool *mempool;
172#ifdef RT_OS_WINDOWS
173 HANDLE hGuestDrv;
174#else
175 int iGuestDrv;
176#endif
177} CRVBOXHGSMIDATA;
178
179#define CR_VBOXHGSMI_BUFFER_MAGIC 0xEDCBA123
180
181typedef struct CRVBOXHGSMIBUFFER {
182 uint32_t magic;
183 union
184 {
185 struct
186 {
187 uint32_t cbLock : 31;
188 uint32_t bIsBuf : 1;
189 };
190 uint32_t Value;
191 };
192 union
193 {
194 PVBOXUHGSMI_BUFFER pBuffer;
195 uint32_t u32Len; /* <- sys mem buf specific */
196 uint64_t u64Align;
197 };
198} CRVBOXHGSMIBUFFER;
199
200typedef struct CRVBOXHGSMI_CLIENT {
201 PVBOXUHGSMI pHgsmi;
202 PVBOXUHGSMI_BUFFER pCmdBuffer;
203 PVBOXUHGSMI_BUFFER pHGBuffer;
204 void *pvHGBuffer;
205 CRBufferPool *bufpool;
206} CRVBOXHGSMI_CLIENT, *PCRVBOXHGSMI_CLIENT;
207
208
209static CRVBOXHGSMIDATA g_crvboxhgsmi = {0,};
210
211DECLINLINE(PCRVBOXHGSMI_CLIENT) _crVBoxHGSMIClientGet()
212{
213 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)VBoxCrHgsmiQueryClient();
214 Assert(pClient);
215 return pClient;
216}
217
218#ifndef RT_OS_WINDOWS
219 #define TRUE true
220 #define FALSE false
221 #define INVALID_HANDLE_VALUE (-1)
222#endif
223
224/* Some forward declarations */
225static void _crVBoxHGSMIReceiveMessage(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient);
226
227/* we still use hgcm for establishing the connection
228 * @todo: join the common code of HGSMI & HGCM */
229/**
230 * Send an HGCM request
231 *
232 * @return VBox status code
233 * @param pvData Data pointer
234 * @param cbData Data size
235 */
236/** @todo use vbglR3DoIOCtl here instead */
237static int crVBoxHGCMCall(void *pvData, unsigned cbData)
238{
239#ifdef IN_GUEST
240
241# ifdef RT_OS_WINDOWS
242 DWORD cbReturned;
243
244 if (DeviceIoControl (g_crvboxhgsmi.hGuestDrv,
245 VBOXGUEST_IOCTL_HGCM_CALL(cbData),
246 pvData, cbData,
247 pvData, cbData,
248 &cbReturned,
249 NULL))
250 {
251 return VINF_SUCCESS;
252 }
253 Assert(0);
254 crDebug("vboxCall failed with %x\n", GetLastError());
255 return VERR_NOT_SUPPORTED;
256# else
257 int rc;
258# if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
259 VBGLBIGREQ Hdr;
260 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
261 Hdr.cbData = cbData;
262 Hdr.pvDataR3 = pvData;
263# if HC_ARCH_BITS == 32
264 Hdr.u32Padding = 0;
265# endif
266 rc = ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), &Hdr);
267# else
268 rc = ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
269# endif
270# ifdef RT_OS_LINUX
271 if (rc == 0)
272# else
273 if (rc >= 0)
274# endif
275 {
276 return VINF_SUCCESS;
277 }
278# ifdef RT_OS_LINUX
279 if (rc >= 0) /* positive values are negated VBox error status codes. */
280 {
281 crWarning("vboxCall failed with VBox status code %d\n", -rc);
282 if (rc==VINF_INTERRUPTED)
283 {
284 RTMSINTERVAL sl;
285 int i;
286
287 for (i=0, sl=50; i<6; i++, sl=sl*2)
288 {
289 RTThreadSleep(sl);
290 rc = ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
291 if (rc==0)
292 {
293 crWarning("vboxCall retry(%i) succeeded", i+1);
294 return VINF_SUCCESS;
295 }
296 else if (rc==VINF_INTERRUPTED)
297 {
298 continue;
299 }
300 else
301 {
302 crWarning("vboxCall retry(%i) failed with VBox status code %d", i+1, -rc);
303 break;
304 }
305 }
306 }
307 }
308 else
309# endif
310 crWarning("vboxCall failed with %x\n", errno);
311 return VERR_NOT_SUPPORTED;
312# endif /*#ifdef RT_OS_WINDOWS*/
313
314#else /*#ifdef IN_GUEST*/
315 crError("crVBoxHGCMCall called on host side!");
316 CRASSERT(FALSE);
317 return VERR_NOT_SUPPORTED;
318#endif
319}
320
321
322/* add sizeof header + page align */
323#define CRVBOXHGSMI_PAGE_ALIGN(_s) (((_s) + 0xfff) & ~0xfff)
324#define CRVBOXHGSMI_BUF_HDR_SIZE() (sizeof (CRVBOXHGSMIBUFFER))
325#define CRVBOXHGSMI_BUF_SIZE(_s) CRVBOXHGSMI_PAGE_ALIGN((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
326#define CRVBOXHGSMI_BUF_LOCK_SIZE(_s) ((_s) + CRVBOXHGSMI_BUF_HDR_SIZE())
327#define CRVBOXHGSMI_BUF_DATA(_p) ((void*)(((CRVBOXHGSMIBUFFER*)(_p)) + 1))
328#define CRVBOXHGSMI_BUF_HDR(_p) (((CRVBOXHGSMIBUFFER*)(_p)) - 1)
329#define CRVBOXHGSMI_BUF_OFFSET(_st2, _st1) ((uint32_t)(((uint8_t*)(_st2)) - ((uint8_t*)(_st1))))
330
331static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLock(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
332{
333 /* in theory it is OK to use one cmd buffer for async cmd submission
334 * because bDiscard flag should result in allocating a new memory backend if the
335 * allocation is still in use.
336 * However, NOTE: since one and the same semaphore sync event is used for completion notification,
337 * for the notification mechanism working as expected
338 * 1. host must complete commands in the same order as it receives them
339 * (to avoid situation when guest receives notification for another command completion)
340 * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
341 * 3. guest must wait for command completion in the same order as it submits them
342 * in case we can not satisfy any of the above, we should introduce multiple command buffers */
343 CRVBOXHGSMIHDR * pHdr;
344 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
345 int rc;
346 fFlags.Value = 0;
347 fFlags.bDiscard = 1;
348 rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
349 AssertRC(rc);
350 if (RT_SUCCESS(rc))
351 return pHdr;
352
353 crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
354 return NULL;
355}
356
357static CRVBOXHGSMIHDR *_crVBoxHGSMICmdBufferLockRo(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
358{
359 /* in theory it is OK to use one cmd buffer for async cmd submission
360 * because bDiscard flag should result in allocating a new memory backend if the
361 * allocation is still in use.
362 * However, NOTE: since one and the same semaphore sync event is used for completion notification,
363 * for the notification mechanism working as expected
364 * 1. host must complete commands in the same order as it receives them
365 * (to avoid situation when guest receives notification for another command completion)
366 * 2. guest must eventually wait for command completion unless he specified bDoNotSignalCompletion
367 * 3. guest must wait for command completion in the same order as it submits them
368 * in case we can not satisfy any of the above, we should introduce multiple command buffers */
369 CRVBOXHGSMIHDR * pHdr;
370 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
371 int rc;
372 fFlags.Value = 0;
373 fFlags.bReadOnly = 1;
374 rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, cbBuffer, fFlags, (void**)&pHdr);
375 AssertRC(rc);
376 if (RT_FAILURE(rc))
377 crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", cbBuffer, rc);
378 return pHdr;
379}
380
381static void _crVBoxHGSMICmdBufferUnlock(PCRVBOXHGSMI_CLIENT pClient)
382{
383 int rc = pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
384 AssertRC(rc);
385 if (RT_FAILURE(rc))
386 crWarning("Failed to Unlock the command buffer rc(%d)\n", rc);
387}
388
389static int32_t _crVBoxHGSMICmdBufferGetRc(PCRVBOXHGSMI_CLIENT pClient)
390{
391 CRVBOXHGSMIHDR * pHdr;
392 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
393 int rc;
394
395 fFlags.Value = 0;
396 fFlags.bReadOnly = 1;
397 rc = pClient->pCmdBuffer->pfnLock(pClient->pCmdBuffer, 0, sizeof (*pHdr), fFlags, (void**)&pHdr);
398 AssertRC(rc);
399 if (RT_FAILURE(rc))
400 {
401 crWarning("Failed to Lock the command buffer of size(%d), rc(%d)\n", sizeof (*pHdr), rc);
402 return rc;
403 }
404
405 rc = pHdr->result;
406 AssertRC(rc);
407 pClient->pCmdBuffer->pfnUnlock(pClient->pCmdBuffer);
408
409 return rc;
410}
411
412DECLINLINE(PVBOXUHGSMI_BUFFER) _crVBoxHGSMIRecvBufGet(PCRVBOXHGSMI_CLIENT pClient)
413{
414 if (pClient->pvHGBuffer)
415 {
416 int rc = pClient->pHGBuffer->pfnUnlock(pClient->pHGBuffer);
417 if (RT_FAILURE(rc))
418 {
419 return NULL;
420 }
421 pClient->pvHGBuffer = NULL;
422 }
423 return pClient->pHGBuffer;
424}
425
426DECLINLINE(void*) _crVBoxHGSMIRecvBufData(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbBuffer)
427{
428 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
429 int rc;
430 Assert(!pClient->pvHGBuffer);
431 fFlags.Value = 0;
432 rc = pClient->pHGBuffer->pfnLock(pClient->pHGBuffer, 0, cbBuffer, fFlags, &pClient->pvHGBuffer);
433 AssertRC(rc);
434 if (RT_SUCCESS(rc))
435 {
436 return pClient->pvHGBuffer;
437 }
438 return NULL;
439}
440
441
442static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufFromMemPtr(void *pvBuf)
443{
444 CRVBOXHGSMIBUFFER *pHdr = CRVBOXHGSMI_BUF_HDR(pvBuf);
445 PVBOXUHGSMI_BUFFER pBuf;
446 int rc;
447
448 CRASSERT(pHdr->magic == CR_VBOXHGSMI_BUFFER_MAGIC);
449 pBuf = pHdr->pBuffer;
450 rc = pBuf->pfnUnlock(pBuf);
451 AssertRC(rc);
452 if (RT_FAILURE(rc))
453 {
454 return NULL;
455 }
456 return pBuf;
457}
458
459static PVBOXUHGSMI_BUFFER _crVBoxHGSMIBufAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
460{
461 PVBOXUHGSMI_BUFFER buf;
462 int rc;
463
464 buf = (PVBOXUHGSMI_BUFFER ) crBufferPoolPop(pClient->bufpool, cbSize);
465
466 if (!buf)
467 {
468 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
469 (void *) pClient->bufpool,
470 cbSize);
471 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, cbSize,
472 VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL,
473 &buf);
474 AssertRC(rc);
475 if (RT_FAILURE(rc))
476 crWarning("Failed to Create a buffer of size(%d), rc(%d)\n", cbSize, rc);
477 }
478 return buf;
479}
480
481static void _crVBoxHGSMIBufFree(PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf)
482{
483 crBufferPoolPush(pClient->bufpool, pBuf, pBuf->cbBuffer);
484}
485
486static CRVBOXHGSMIBUFFER* _crVBoxHGSMISysMemAlloc(uint32_t cbSize)
487{
488 CRVBOXHGSMIBUFFER *pBuf;
489#ifdef CHROMIUM_THREADSAFE
490 crLockMutex(&g_crvboxhgsmi.mutex);
491#endif
492 pBuf = crBufferPoolPop(g_crvboxhgsmi.mempool, cbSize);
493 if (!pBuf)
494 {
495 pBuf = (CRVBOXHGSMIBUFFER*)crAlloc(CRVBOXHGSMI_BUF_HDR_SIZE() + cbSize);
496 Assert(pBuf);
497 if (pBuf)
498 {
499 pBuf->magic = CR_VBOXHGSMI_BUFFER_MAGIC;
500 pBuf->cbLock = cbSize;
501 pBuf->bIsBuf = false;
502 pBuf->u32Len = 0;
503 }
504 }
505#ifdef CHROMIUM_THREADSAFE
506 crUnlockMutex(&g_crvboxhgsmi.mutex);
507#endif
508 return pBuf;
509}
510
511static void *_crVBoxHGSMIDoAlloc(PCRVBOXHGSMI_CLIENT pClient, uint32_t cbSize)
512{
513 PVBOXUHGSMI_BUFFER buf;
514 CRVBOXHGSMIBUFFER *pData = NULL;
515 int rc;
516
517 buf = _crVBoxHGSMIBufAlloc(pClient, CRVBOXHGSMI_BUF_SIZE(cbSize));
518 Assert(buf);
519 if (buf)
520 {
521 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
522 buf->pvUserData = pClient;
523 fFlags.Value = 0;
524 fFlags.bDiscard = 1;
525 rc = buf->pfnLock(buf, 0, CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize), fFlags, (void**)&pData);
526 if (RT_SUCCESS(rc))
527 {
528 pData->magic = CR_VBOXHGSMI_BUFFER_MAGIC;
529 pData->cbLock = CRVBOXHGSMI_BUF_LOCK_SIZE(cbSize);
530 pData->bIsBuf = true;
531 pData->pBuffer = buf;
532 }
533 else
534 {
535 crWarning("Failed to Lock the buffer, rc(%d)\n", rc);
536 }
537 }
538
539 return CRVBOXHGSMI_BUF_DATA(pData);
540
541}
542static void *crVBoxHGSMIAlloc(CRConnection *conn)
543{
544 PCRVBOXHGSMI_CLIENT pClient;
545 void *pvBuf;
546
547 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
548
549 pClient = _crVBoxHGSMIClientGet();
550 pvBuf = _crVBoxHGSMIDoAlloc(pClient, conn->buffer_size);
551 Assert(pvBuf);
552
553 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
554
555 return pvBuf;
556}
557
558DECLINLINE(void) _crVBoxHGSMIFillCmd(VBOXUHGSMI_BUFFER_SUBMIT *pSubm, PCRVBOXHGSMI_CLIENT pClient, uint32_t cbData)
559{
560 pSubm->pBuf = pClient->pCmdBuffer;
561 pSubm->offData = 0;
562 pSubm->cbData = cbData;
563 pSubm->fFlags.Value = 0;
564 pSubm->fFlags.bDoNotRetire = 1;
565// pSubm->fFlags.bDoNotSignalCompletion = 1; /* <- we do not need that actually since
566// * in case we want completion,
567// * we will block in _crVBoxHGSMICmdBufferGetRc (when locking the buffer)
568// * which is needed for getting the result */
569}
570
571#ifdef RT_OS_WINDOWS
572#define CRVBOXHGSMI_BUF_WAIT(_pBub) WaitForSingleObject((_pBub)->hSynch, INFINITE);
573#else
574# error "Port Me!!"
575#endif
576
577DECLINLINE(void) _crVBoxHGSMIWaitCmd(PCRVBOXHGSMI_CLIENT pClient)
578{
579 int rc = CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
580 Assert(rc == 0);
581}
582
583static void _crVBoxHGSMIWriteExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, PVBOXUHGSMI_BUFFER pBuf, uint32_t offStart, unsigned int len)
584{
585 int rc;
586 int32_t callRes;
587 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
588
589#ifdef IN_GUEST
590 if (conn->u32InjectClientID)
591 {
592 CRVBOXHGSMIINJECT *parms = (CRVBOXHGSMIINJECT *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
593 Assert(parms);
594 if (!parms)
595 {
596 return;
597 }
598
599 parms->hdr.result = VERR_WRONG_ORDER;
600 parms->hdr.u32ClientID = conn->u32ClientID;
601 parms->hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
602// parms->hdr.u32Reserved = 0;
603
604 parms->u32ClientID = conn->u32InjectClientID;
605
606 parms->iBuffer = 1;
607 _crVBoxHGSMICmdBufferUnlock(pClient);
608
609 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
610
611 aSubmit[1].pBuf = pBuf;
612 aSubmit[1].offData = offStart;
613 aSubmit[1].cbData = len;
614 aSubmit[1].fFlags.Value = 0;
615 aSubmit[1].fFlags.bHostReadOnly = 1;
616
617 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
618 AssertRC(rc);
619 if (RT_SUCCESS(rc))
620 {
621 _crVBoxHGSMIWaitCmd(pClient);
622 /* @todo: do we need to wait for completion actually?
623 * NOTE: in case we do not need completion,
624 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
625// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
626
627 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
628 }
629 }
630 else
631#endif
632 {
633 CRVBOXHGSMIWRITE * parms = (CRVBOXHGSMIWRITE *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));;
634
635 parms->hdr.result = VERR_WRONG_ORDER;
636 parms->hdr.u32ClientID = conn->u32ClientID;
637 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
638// parms->hdr.u32Reserved = 0;
639
640 parms->iBuffer = 1;
641 _crVBoxHGSMICmdBufferUnlock(pClient);
642
643 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
644
645 aSubmit[1].pBuf = pBuf;
646 aSubmit[1].offData = offStart;
647 aSubmit[1].cbData = len;
648 aSubmit[1].fFlags.Value = 0;
649 aSubmit[1].fFlags.bHostReadOnly = 1;
650
651 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
652 AssertRC(rc);
653 if (RT_SUCCESS(rc))
654 {
655 _crVBoxHGSMIWaitCmd(pClient);
656 /* @todo: do we need to wait for completion actually?
657 * NOTE: in case we do not need completion,
658 * we MUST specify bDoNotSignalCompletion flag for the command buffer */
659// CRVBOXHGSMI_BUF_WAIT(pClient->pCmdBuffer);
660
661 callRes = _crVBoxHGSMICmdBufferGetRc(pClient);
662 }
663 }
664
665 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
666 {
667 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
668 }
669}
670
671static void crVBoxHGSMIWriteExact(CRConnection *conn, const void *buf, unsigned int len)
672{
673 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
674 Assert(0);
675
676 CRASSERT(0);
677// PCRVBOXHGSMI_CLIENT pClient;
678// PVBOXUHGSMI_BUFFER pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
679// if (!pBuf)
680// return;
681// pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
682// _crVBoxHGSMIWriteExact(conn, pClient, pBuf, 0, len);
683// _crVBoxHGSMIBufFree(pClient, pBuf);
684 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
685}
686
687static void _crVBoxHGSMIPollHost(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
688{
689 CRVBOXHGSMIREAD *parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
690 int rc;
691 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[2];
692 PVBOXUHGSMI_BUFFER pRecvBuffer;
693 uint32_t cbBuffer;
694
695 Assert(parms);
696
697 parms->hdr.result = VERR_WRONG_ORDER;
698 parms->hdr.u32ClientID = conn->u32ClientID;
699 parms->hdr.u32Function = SHCRGL_GUEST_FN_READ;
700// parms->hdr.u32Reserved = 0;
701
702 CRASSERT(!conn->pBuffer); //make sure there's no data to process
703 parms->iBuffer = 1;
704 parms->cbBuffer = 0;
705
706 _crVBoxHGSMICmdBufferUnlock(pClient);
707
708 pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
709 Assert(pRecvBuffer);
710 if (!pRecvBuffer)
711 return;
712
713 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
714
715 aSubmit[1].pBuf = pRecvBuffer;
716 aSubmit[1].offData = 0;
717 aSubmit[1].cbData = pRecvBuffer->cbBuffer;
718 aSubmit[1].fFlags.Value = 0;
719 aSubmit[1].fFlags.bHostWriteOnly = 1;
720
721 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 2);
722 AssertRC(rc);
723 if (RT_FAILURE(rc))
724 {
725 crWarning("pfnBufferSubmitAsynch failed with %d \n", rc);
726 return;
727 }
728
729 _crVBoxHGSMIWaitCmd(pClient);
730
731 parms = (CRVBOXHGSMIREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
732 Assert(parms);
733 if (!parms)
734 {
735 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
736 return;
737 }
738
739 if (RT_SUCCESS(parms->hdr.result))
740 cbBuffer = parms->cbBuffer;
741 else
742 cbBuffer = 0;
743
744 _crVBoxHGSMICmdBufferUnlock(pClient);
745
746 if (cbBuffer)
747 {
748 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbBuffer);
749 Assert(pvData);
750 if (pvData)
751 {
752 conn->pBuffer = pvData;
753 conn->cbBuffer = cbBuffer;
754 }
755 }
756}
757
758static void _crVBoxHGSMIReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
759{
760 _crVBoxHGSMIPollHost(conn, pClient);
761
762 if (conn->cbBuffer)
763 _crVBoxHGSMIReceiveMessage(conn, pClient);
764}
765
766/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
767 * This halves the number of HGCM calls we do,
768 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
769 */
770static void
771_crVBoxHGSMIWriteReadExact(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient, void *buf, uint32_t offBuffer, unsigned int len, bool bIsBuffer)
772{
773 CRVBOXHGSMIWRITEREAD *parms = (CRVBOXHGSMIWRITEREAD*)_crVBoxHGSMICmdBufferLock(pClient, sizeof (*parms));
774 int rc;
775 VBOXUHGSMI_BUFFER_SUBMIT aSubmit[3];
776 PVBOXUHGSMI_BUFFER pBuf = NULL;
777 VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags;
778// uint32_t cbBuffer;
779
780 parms->hdr.result = VERR_WRONG_ORDER;
781 parms->hdr.u32ClientID = conn->u32ClientID;
782 parms->hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
783// parms->hdr.u32Reserved = 0;
784
785 parms->iBuffer = 1;
786
787 CRASSERT(!conn->pBuffer); //make sure there's no data to process
788 parms->iWriteback = 2;
789 parms->cbWriteback = 0;
790
791 _crVBoxHGSMICmdBufferUnlock(pClient);
792
793 if (!bIsBuffer)
794 {
795 void *pvBuf;
796 pBuf = _crVBoxHGSMIBufAlloc(pClient, len);
797 Assert(pBuf);
798 if (!pBuf)
799 return;
800
801 Assert(!offBuffer);
802
803 offBuffer = 0;
804 fFlags.Value = 0;
805 fFlags.bDiscard = 1;
806 fFlags.bWriteOnly = 1;
807 rc = pBuf->pfnLock(pBuf, 0, len, fFlags, &pvBuf);
808 AssertRC(rc);
809 if (RT_SUCCESS(rc))
810 {
811 memcpy(pvBuf, buf, len);
812 rc = pBuf->pfnUnlock(pBuf);
813 AssertRC(rc);
814 CRASSERT(RT_SUCCESS(rc));
815 }
816 else
817 {
818 _crVBoxHGSMIBufFree(pClient, pBuf);
819 return;
820 }
821 }
822 else
823 {
824 pBuf = (PVBOXUHGSMI_BUFFER)buf;
825 }
826
827 do
828 {
829 PVBOXUHGSMI_BUFFER pRecvBuffer = _crVBoxHGSMIRecvBufGet(pClient);
830 Assert(pRecvBuffer);
831 if (!pRecvBuffer)
832 return;
833
834 _crVBoxHGSMIFillCmd(&aSubmit[0], pClient, sizeof (*parms));
835
836 aSubmit[1].pBuf = pBuf;
837 aSubmit[1].offData = offBuffer;
838 aSubmit[1].cbData = len;
839 aSubmit[1].fFlags.Value = 0;
840 aSubmit[1].fFlags.bHostReadOnly = 1;
841
842 aSubmit[2].pBuf = pRecvBuffer;
843 aSubmit[2].offData = 0;
844 aSubmit[2].cbData = pRecvBuffer->cbBuffer;
845 aSubmit[2].fFlags.Value = 0;
846
847 rc = pClient->pHgsmi->pfnBufferSubmitAsynch(pClient->pHgsmi, aSubmit, 3);
848 AssertRC(rc);
849 if (RT_FAILURE(rc))
850 {
851 crWarning("pfnBufferSubmitAsynch failed with %d \n", rc);
852 break;
853 }
854
855 _crVBoxHGSMIWaitCmd(pClient);
856
857 parms = (CRVBOXHGSMIWRITEREAD *)_crVBoxHGSMICmdBufferLockRo(pClient, sizeof (*parms));
858 Assert(parms);
859 if (parms)
860 {
861 uint32_t cbWriteback = parms->cbWriteback;
862 rc = parms->hdr.result;
863 _crVBoxHGSMICmdBufferUnlock(pClient);
864#ifdef DEBUG
865 parms = NULL;
866#endif
867 if (RT_SUCCESS(rc))
868 {
869 if (cbWriteback)
870 {
871 void *pvData = _crVBoxHGSMIRecvBufData(pClient, cbWriteback);
872 Assert(pvData);
873 if (pvData)
874 {
875 conn->pBuffer = pvData;
876 conn->cbBuffer = cbWriteback;
877 _crVBoxHGSMIReceiveMessage(conn, pClient);
878 }
879 }
880 }
881 else if (VERR_BUFFER_OVERFLOW == rc)
882 {
883 PVBOXUHGSMI_BUFFER pOldBuf = pClient->pHGBuffer;
884 Assert(!pClient->pvHGBuffer);
885 CRASSERT(cbWriteback>pClient->pHGBuffer->cbBuffer);
886 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, cbWriteback);
887
888 rc = pClient->pHgsmi->pfnBufferCreate(pClient->pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(cbWriteback),
889 VBOXUHGSMI_SYNCHOBJECT_TYPE_NONE, NULL, &pClient->pHGBuffer);
890 AssertRC(rc);
891 CRASSERT(RT_SUCCESS(rc));
892 if (RT_SUCCESS(rc))
893 {
894 rc = pOldBuf->pfnDestroy(pOldBuf);
895 CRASSERT(RT_SUCCESS(rc));
896
897 _crVBoxHGSMIReadExact(conn, pClient/*, cbWriteback*/);
898 }
899 }
900 else
901 {
902 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x \n", len, rc);
903 }
904 }
905 else
906 {
907 crWarning("_crVBoxHGSMICmdBufferLockRo failed\n");
908 break;
909 }
910 } while (0);
911
912 if (!bIsBuffer)
913 _crVBoxHGSMIBufFree(pClient, pBuf);
914}
915
916static void crVBoxHGSMISend(CRConnection *conn, void **bufp,
917 const void *start, unsigned int len)
918{
919 PCRVBOXHGSMI_CLIENT pClient;
920 PVBOXUHGSMI_BUFFER pBuf;
921
922 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
923
924 if (!bufp) /* We're sending a user-allocated buffer. */
925 {
926 pClient = _crVBoxHGSMIClientGet();
927#ifndef IN_GUEST
928 //@todo remove temp buffer allocation in unpacker
929 /* we're at the host side, so just store data until guest polls us */
930 _crVBoxHGCMWriteBytes(conn, start, len);
931#else
932 CRASSERT(!conn->u32InjectClientID);
933 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
934 _crVBoxHGSMIWriteReadExact(conn, pClient, (void*)start, 0, len, false);
935#endif
936 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
937 return;
938 }
939
940 /* The region [start .. start + len + 1] lies within a buffer that
941 * was allocated with crVBoxHGCMAlloc() and can be put into the free
942 * buffer pool when we're done sending it.
943 */
944
945 pBuf = _crVBoxHGSMIBufFromMemPtr(*bufp);
946 Assert(pBuf);
947 if (!pBuf)
948 {
949 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
950 return;
951 }
952
953 pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
954
955 /* Length would be passed as part of HGCM pointer description
956 * No need to prepend it to the buffer
957 */
958#ifdef IN_GUEST
959 if (conn->u32InjectClientID)
960 {
961 _crVBoxHGSMIWriteExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len);
962 }
963 else
964#endif
965 {
966 _crVBoxHGSMIWriteReadExact(conn, pClient, pBuf, CRVBOXHGSMI_BUF_OFFSET(start, *bufp) + CRVBOXHGSMI_BUF_HDR_SIZE(), len, true);
967 }
968
969 /* Reclaim this pointer for reuse */
970 _crVBoxHGSMIBufFree(pClient, pBuf);
971 /* Since the buffer's now in the 'free' buffer pool, the caller can't
972 * use it any more. Setting bufp to NULL will make sure the caller
973 * doesn't try to re-use the buffer.
974 */
975 *bufp = NULL;
976
977 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
978}
979
980static void crVBoxHGSMISingleRecv(CRConnection *conn, void *buf, unsigned int len)
981{
982 PCRVBOXHGSMI_CLIENT pClient;
983 PVBOXUHGSMI_BUFFER pBuf;
984 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
985 pBuf = _crVBoxHGSMIBufFromMemPtr(buf);
986 Assert(pBuf);
987 Assert(0);
988 CRASSERT(0);
989 if (!pBuf)
990 {
991 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
992 return;
993 }
994 pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
995 _crVBoxHGSMIReadExact(conn, pClient);
996 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
997}
998
999static void _crVBoxHGSMIFree(CRConnection *conn, void *buf)
1000{
1001 CRVBOXHGSMIBUFFER *hgsmi_buffer = (CRVBOXHGSMIBUFFER *) buf - 1;
1002
1003 CRASSERT(hgsmi_buffer->magic == CR_VBOXHGSMI_BUFFER_MAGIC);
1004
1005 if (hgsmi_buffer->bIsBuf)
1006 {
1007 PVBOXUHGSMI_BUFFER pBuf = hgsmi_buffer->pBuffer;
1008 PCRVBOXHGSMI_CLIENT pClient = (PCRVBOXHGSMI_CLIENT)pBuf->pvUserData;
1009 pBuf->pfnUnlock(pBuf);
1010 _crVBoxHGSMIBufFree(pClient, pBuf);
1011 }
1012 else
1013 {
1014 /*@todo wrong len for redir buffers*/
1015 conn->recv_credits += hgsmi_buffer->u32Len;
1016
1017#ifdef CHROMIUM_THREADSAFE
1018 crLockMutex(&g_crvboxhgsmi.mutex);
1019#endif
1020 crBufferPoolPush(g_crvboxhgsmi.mempool, hgsmi_buffer, hgsmi_buffer->cbLock);
1021#ifdef CHROMIUM_THREADSAFE
1022 crUnlockMutex(&g_crvboxhgsmi.mutex);
1023#endif
1024 }
1025}
1026static void crVBoxHGSMIFree(CRConnection *conn, void *buf)
1027{
1028 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1029 _crVBoxHGSMIFree(conn, buf);
1030 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1031}
1032
1033static void _crVBoxHGSMIReceiveMessage(CRConnection *conn, PCRVBOXHGSMI_CLIENT pClient)
1034{
1035 uint32_t len;
1036 CRVBOXHGSMIBUFFER* pSysBuf;
1037 CRMessage *msg;
1038 CRMessageType cached_type;
1039
1040 len = conn->cbBuffer;
1041 Assert(len > 0);
1042 Assert(conn->pBuffer);
1043 CRASSERT(len > 0);
1044 CRASSERT(conn->pBuffer);
1045
1046#ifndef IN_GUEST
1047 if (conn->allow_redir_ptr)
1048 {
1049#endif //IN_GUEST
1050 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
1051
1052 pSysBuf = _crVBoxHGSMISysMemAlloc( conn->buffer_size );
1053 pSysBuf->u32Len = sizeof(CRMessageRedirPtr);
1054
1055 msg = (CRMessage *)CRVBOXHGSMI_BUF_DATA(pSysBuf);
1056
1057 msg->header.type = CR_MESSAGE_REDIR_PTR;
1058 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
1059 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
1060
1061 cached_type = msg->redirptr.pMessage->type;
1062
1063 conn->cbBuffer = 0;
1064 conn->pBuffer = NULL;
1065#ifndef IN_GUEST
1066 }
1067 else
1068 {
1069 if ( len <= conn->buffer_size )
1070 {
1071 /* put in pre-allocated buffer */
1072 hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
1073 }
1074 else
1075 {
1076 /* allocate new buffer,
1077 * not using pool here as it's most likely one time transfer of huge texture
1078 */
1079 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
1080 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
1081 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
1082 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
1083# ifdef RT_OS_WINDOWS
1084 hgcm_buffer->pDDS = NULL;
1085# endif
1086 }
1087
1088 hgcm_buffer->len = len;
1089
1090 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
1091
1092 msg = (CRMessage *) (hgcm_buffer + 1);
1093 cached_type = msg->header.type;
1094 }
1095#endif //IN_GUEST
1096
1097 conn->recv_credits -= len;
1098 conn->total_bytes_recv += len;
1099 conn->recv_count++;
1100
1101 crNetDispatchMessage( g_crvboxhgsmi.recv_list, conn, msg, len );
1102
1103 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
1104 * OOB messages are the programmer's problem. -- Humper 12/17/01
1105 */
1106 if (cached_type != CR_MESSAGE_OPCODES
1107 && cached_type != CR_MESSAGE_OOB
1108 && cached_type != CR_MESSAGE_GATHER)
1109 {
1110 _crVBoxHGSMIFree(conn, msg);
1111 }
1112}
1113
1114static void crVBoxHGSMIReceiveMessage(CRConnection *conn)
1115{
1116 PCRVBOXHGSMI_CLIENT pClient;
1117 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1118
1119 pClient = _crVBoxHGSMIClientGet();
1120
1121 Assert(pClient);
1122 Assert(0);
1123
1124 _crVBoxHGSMIReceiveMessage(conn, pClient);
1125 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1126}
1127/*
1128 * Called on host side only, to "accept" client connection
1129 */
1130static void crVBoxHGSMIAccept( CRConnection *conn, const char *hostname, unsigned short port )
1131{
1132 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1133 Assert(0);
1134
1135 CRASSERT(conn && conn->pHostBuffer);
1136#ifdef IN_GUEST
1137 CRASSERT(FALSE);
1138#endif
1139 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1140}
1141
1142static int crVBoxHGSMISetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
1143{
1144 CRVBOXHGCMSETVERSION parms;
1145 int rc;
1146
1147 parms.hdr.result = VERR_WRONG_ORDER;
1148 parms.hdr.u32ClientID = conn->u32ClientID;
1149 parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_VERSION;
1150 parms.hdr.cParms = SHCRGL_CPARMS_SET_VERSION;
1151
1152 parms.vMajor.type = VMMDevHGCMParmType_32bit;
1153 parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
1154 parms.vMinor.type = VMMDevHGCMParmType_32bit;
1155 parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
1156
1157 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1158
1159 AssertRC(rc);
1160
1161 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1162 {
1163 crWarning("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
1164 parms.vMajor.u.value32, parms.vMinor.u.value32);
1165 return FALSE;
1166 }
1167
1168 conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
1169 conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
1170
1171 return TRUE;
1172}
1173
1174static int crVBoxHGSMISetPID(CRConnection *conn, unsigned long long pid)
1175{
1176 CRVBOXHGCMSETPID parms;
1177 int rc;
1178
1179 parms.hdr.result = VERR_WRONG_ORDER;
1180 parms.hdr.u32ClientID = conn->u32ClientID;
1181 parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_PID;
1182 parms.hdr.cParms = SHCRGL_CPARMS_SET_PID;
1183
1184 parms.u64PID.type = VMMDevHGCMParmType_64bit;
1185 parms.u64PID.u.value64 = pid;
1186
1187 rc = crVBoxHGCMCall(&parms, sizeof(parms));
1188
1189 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
1190 {
1191 Assert(0);
1192
1193 crWarning("SHCRGL_GUEST_FN_SET_PID failed!");
1194 return FALSE;
1195 }
1196
1197 return TRUE;
1198}
1199
1200/**
1201 * The function that actually connects. This should only be called by clients,
1202 * guests in vbox case.
1203 * Servers go through crVBoxHGCMAccept;
1204 */
1205/*@todo use vbglR3Something here */
1206static int crVBoxHGSMIDoConnect( CRConnection *conn )
1207{
1208#ifdef IN_GUEST
1209 VBoxGuestHGCMConnectInfo info;
1210
1211#ifdef RT_OS_WINDOWS
1212 DWORD cbReturned;
1213 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1214
1215 if (g_crvboxhgsmi.hGuestDrv == INVALID_HANDLE_VALUE)
1216 {
1217 /* open VBox guest driver */
1218 g_crvboxhgsmi.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
1219 GENERIC_READ | GENERIC_WRITE,
1220 FILE_SHARE_READ | FILE_SHARE_WRITE,
1221 NULL,
1222 OPEN_EXISTING,
1223 FILE_ATTRIBUTE_NORMAL,
1224 NULL);
1225
1226 /* @todo check if we could rollback to softwareopengl */
1227 if (g_crvboxhgsmi.hGuestDrv == INVALID_HANDLE_VALUE)
1228 {
1229 Assert(0);
1230 crDebug("could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
1231 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1232 return FALSE;
1233 }
1234 }
1235#else
1236 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1237
1238 if (g_crvboxhgsmi.iGuestDrv == INVALID_HANDLE_VALUE)
1239 {
1240 g_crvboxhgsmi.iGuestDrv = open(VBOXGUEST_USER_DEVICE_NAME, O_RDWR, 0);
1241 if (g_crvboxhgsmi.iGuestDrv == INVALID_HANDLE_VALUE)
1242 {
1243 crDebug("could not open Guest Additions kernel module! rc = %d\n", errno);
1244 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1245 return FALSE;
1246 }
1247 }
1248#endif
1249
1250 memset (&info, 0, sizeof (info));
1251 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
1252 strcpy (info.Loc.u.host.achName, "VBoxSharedCrOpenGL");
1253
1254#ifdef RT_OS_WINDOWS
1255 if (DeviceIoControl(g_crvboxhgsmi.hGuestDrv,
1256 VBOXGUEST_IOCTL_HGCM_CONNECT,
1257 &info, sizeof (info),
1258 &info, sizeof (info),
1259 &cbReturned,
1260 NULL))
1261#elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1262 VBGLBIGREQ Hdr;
1263 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
1264 Hdr.cbData = sizeof(info);
1265 Hdr.pvDataR3 = &info;
1266# if HC_ARCH_BITS == 32
1267 Hdr.u32Padding = 0;
1268# endif
1269 if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &Hdr) >= 0)
1270#else
1271 if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info)) >= 0)
1272#endif
1273 {
1274 if (info.result == VINF_SUCCESS)
1275 {
1276 int rc;
1277 conn->u32ClientID = info.u32ClientID;
1278 crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
1279
1280 rc = crVBoxHGSMISetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
1281 if (!rc)
1282 {
1283 return rc;
1284 }
1285#ifdef RT_OS_WINDOWS
1286 rc = crVBoxHGCMSetPID(conn, GetCurrentProcessId());
1287#else
1288 rc = crVBoxHGCMSetPID(conn, crGetPID());
1289#endif
1290 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1291 return rc;
1292 }
1293 else
1294 {
1295 Assert(0);
1296 crDebug("HGCM connect failed with rc=0x%x\n", info.result);
1297 }
1298 }
1299 else
1300 {
1301#ifdef RT_OS_WINDOWS
1302 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", GetLastError());
1303#else
1304 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", errno);
1305#endif
1306 }
1307
1308 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1309
1310 return FALSE;
1311#else /*#ifdef IN_GUEST*/
1312 crError("crVBoxHGSMIDoConnect called on host side!");
1313 CRASSERT(FALSE);
1314 return FALSE;
1315#endif
1316}
1317
1318/*@todo same, replace DeviceIoControl with vbglR3DoIOCtl */
1319static void crVBoxHGSMIDoDisconnect( CRConnection *conn )
1320{
1321#ifdef IN_GUEST
1322 VBoxGuestHGCMDisconnectInfo info;
1323# ifdef RT_OS_WINDOWS
1324 DWORD cbReturned;
1325# endif
1326 int i;
1327#endif
1328 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1329
1330 if (conn->pHostBuffer)
1331 {
1332 crFree(conn->pHostBuffer);
1333 conn->pHostBuffer = NULL;
1334 conn->cbHostBuffer = 0;
1335 conn->cbHostBufferAllocated = 0;
1336 }
1337
1338 conn->pBuffer = NULL;
1339 conn->cbBuffer = 0;
1340
1341 //@todo hold lock here?
1342 if (conn->type == CR_VBOXHGCM)
1343 {
1344 --g_crvboxhgsmi.num_conns;
1345
1346 if (conn->index < g_crvboxhgsmi.num_conns)
1347 {
1348 g_crvboxhgsmi.conns[conn->index] = g_crvboxhgsmi.conns[g_crvboxhgsmi.num_conns];
1349 g_crvboxhgsmi.conns[conn->index]->index = conn->index;
1350 }
1351 else g_crvboxhgsmi.conns[conn->index] = NULL;
1352
1353 conn->type = CR_NO_CONNECTION;
1354 }
1355
1356#ifndef IN_GUEST
1357#else /* IN_GUEST */
1358 if (conn->u32ClientID)
1359 {
1360 memset (&info, 0, sizeof (info));
1361 info.u32ClientID = conn->u32ClientID;
1362
1363# ifdef RT_OS_WINDOWS
1364 if ( !DeviceIoControl(g_crvboxhgsmi.hGuestDrv,
1365 VBOXGUEST_IOCTL_HGCM_DISCONNECT,
1366 &info, sizeof (info),
1367 &info, sizeof (info),
1368 &cbReturned,
1369 NULL) )
1370 {
1371 crDebug("Disconnect failed with %x\n", GetLastError());
1372 }
1373# elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
1374 VBGLBIGREQ Hdr;
1375 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
1376 Hdr.cbData = sizeof(info);
1377 Hdr.pvDataR3 = &info;
1378# if HC_ARCH_BITS == 32
1379 Hdr.u32Padding = 0;
1380# endif
1381 if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Hdr) >= 0)
1382# else
1383 if (ioctl(g_crvboxhgsmi.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info, sizeof (info)) < 0)
1384 {
1385 crDebug("Disconnect failed with %x\n", errno);
1386 }
1387# endif
1388
1389 conn->u32ClientID = 0;
1390 }
1391
1392 /* see if any connections remain */
1393 for (i = 0; i < g_crvboxhgsmi.num_conns; i++)
1394 if (g_crvboxhgsmi.conns[i] && g_crvboxhgsmi.conns[i]->type != CR_NO_CONNECTION)
1395 break;
1396
1397 /* close guest additions driver*/
1398 if (i>=g_crvboxhgsmi.num_conns)
1399 {
1400# ifdef RT_OS_WINDOWS
1401 CloseHandle(g_crvboxhgsmi.hGuestDrv);
1402 g_crvboxhgsmi.hGuestDrv = INVALID_HANDLE_VALUE;
1403# else
1404 close(g_crvboxhgsmi.iGuestDrv);
1405 g_crvboxhgsmi.iGuestDrv = INVALID_HANDLE_VALUE;
1406# endif
1407 }
1408 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1409#endif /* IN_GUEST */
1410}
1411
1412static void crVBoxHGSMIInstantReclaim(CRConnection *conn, CRMessage *mess)
1413{
1414 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1415 Assert(0);
1416
1417 _crVBoxHGSMIFree(conn, mess);
1418 CRASSERT(FALSE);
1419
1420 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1421}
1422
1423static void crVBoxHGSMIHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
1424{
1425 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1426 Assert(0);
1427
1428 CRASSERT(FALSE);
1429 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1430}
1431
1432DECLCALLBACK(HVBOXCRHGSMI_CLIENT) _crVBoxHGSMIClientCreate(PVBOXUHGSMI pHgsmi)
1433{
1434 PCRVBOXHGSMI_CLIENT pClient = crAlloc(sizeof (CRVBOXHGSMI_CLIENT));
1435
1436 if (pClient)
1437 {
1438 int rc;
1439 pClient->pHgsmi = pHgsmi;
1440 rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(1),
1441 VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT,
1442 NULL,
1443 &pClient->pCmdBuffer);
1444 AssertRC(rc);
1445 if (RT_SUCCESS(rc))
1446 {
1447 rc = pHgsmi->pfnBufferCreate(pHgsmi, CRVBOXHGSMI_PAGE_ALIGN(0x800000),
1448 VBOXUHGSMI_SYNCHOBJECT_TYPE_EVENT,
1449 NULL,
1450 &pClient->pHGBuffer);
1451 AssertRC(rc);
1452 if (RT_SUCCESS(rc))
1453 {
1454 pClient->pvHGBuffer = NULL;
1455 pClient->bufpool = crBufferPoolInit(16);
1456 return (HVBOXCRHGSMI_CLIENT) pClient;
1457 }
1458 }
1459 }
1460
1461 return NULL;
1462}
1463
1464DECLCALLBACK(void) _crVBoxHGSMIClientDestroy(HVBOXCRHGSMI_CLIENT hClient)
1465{
1466 Assert(0);
1467
1468 /* @todo */
1469}
1470
1471
1472bool crVBoxHGSMIInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
1473{
1474 /* static */ int bHasHGSMI = -1; /* do it for all connections */
1475 (void) mtu;
1476
1477 if (bHasHGSMI < 0)
1478 {
1479 int rc;
1480 VBOXCRHGSMI_CALLBACKS Callbacks;
1481 Callbacks.pfnClientCreate = _crVBoxHGSMIClientCreate;
1482 Callbacks.pfnClientDestroy = _crVBoxHGSMIClientDestroy;
1483 rc = VBoxCrHgsmiInit(&Callbacks);
1484 AssertRC(rc);
1485 if (RT_SUCCESS(rc))
1486 bHasHGSMI = 1;
1487 else
1488 bHasHGSMI = 0;
1489 }
1490
1491 Assert(bHasHGSMI);
1492
1493 if (!bHasHGSMI)
1494 {
1495#ifdef DEBUG_misha
1496 AssertRelease(0);
1497#endif
1498 return false;
1499 }
1500
1501 g_crvboxhgsmi.recv_list = rfl;
1502 g_crvboxhgsmi.close_list = cfl;
1503 if (g_crvboxhgsmi.initialized)
1504 {
1505 return true;
1506 }
1507
1508 g_crvboxhgsmi.initialized = 1;
1509
1510 g_crvboxhgsmi.num_conns = 0;
1511 g_crvboxhgsmi.conns = NULL;
1512 g_crvboxhgsmi.mempool = crBufferPoolInit(16);
1513
1514 /* Can't open VBox guest driver here, because it gets called for host side as well */
1515 /*@todo as we have 2 dll versions, can do it now.*/
1516
1517#ifdef RT_OS_WINDOWS
1518 g_crvboxhgsmi.hGuestDrv = INVALID_HANDLE_VALUE;
1519#else
1520 g_crvboxhgsmi.iGuestDrv = INVALID_HANDLE_VALUE;
1521#endif
1522
1523#ifdef CHROMIUM_THREADSAFE
1524 crInitMutex(&g_crvboxhgsmi.mutex);
1525 crInitMutex(&g_crvboxhgsmi.recvmutex);
1526#endif
1527
1528 return true;
1529}
1530
1531/* Callback function used to free buffer pool entries */
1532void _crVBoxHGSMISysMemFree(void *data)
1533{
1534 Assert(0);
1535
1536 crFree(data);
1537}
1538
1539void crVBoxHGSMITearDown(void)
1540{
1541 int32_t i, cCons;
1542
1543 Assert(0);
1544
1545 if (!g_crvboxhgsmi.initialized) return;
1546
1547 /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
1548 * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
1549 * order of their connection.
1550 */
1551 cCons = g_crvboxhgsmi.num_conns;
1552 for (i=0; i<cCons; i++)
1553 {
1554 /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
1555 crNetDisconnect(g_crvboxhgsmi.conns[0]);
1556 }
1557 CRASSERT(0==g_crvboxhgsmi.num_conns);
1558
1559#ifdef CHROMIUM_THREADSAFE
1560 crFreeMutex(&g_crvboxhgsmi.mutex);
1561 crFreeMutex(&g_crvboxhgsmi.recvmutex);
1562#endif
1563
1564 if (g_crvboxhgsmi.mempool)
1565 crBufferPoolCallbackFree(g_crvboxhgsmi.mempool, _crVBoxHGSMISysMemFree);
1566 g_crvboxhgsmi.mempool = NULL;
1567
1568 g_crvboxhgsmi.initialized = 0;
1569
1570 crFree(g_crvboxhgsmi.conns);
1571 g_crvboxhgsmi.conns = NULL;
1572}
1573
1574void crVBoxHGSMIConnection(CRConnection *conn)
1575{
1576 int i, found = 0;
1577 int n_bytes;
1578
1579 CRASSERT(g_crvboxhgsmi.initialized);
1580
1581 conn->type = CR_VBOXHGCM;
1582 conn->Alloc = crVBoxHGSMIAlloc;
1583 conn->Send = crVBoxHGSMISend;
1584 conn->SendExact = crVBoxHGSMIWriteExact;
1585 conn->Recv = crVBoxHGSMISingleRecv;
1586 conn->RecvMsg = crVBoxHGSMIReceiveMessage;
1587 conn->Free = crVBoxHGSMIFree;
1588 conn->Accept = crVBoxHGSMIAccept;
1589 conn->Connect = crVBoxHGSMIDoConnect;
1590 conn->Disconnect = crVBoxHGSMIDoDisconnect;
1591 conn->InstantReclaim = crVBoxHGSMIInstantReclaim;
1592 conn->HandleNewMessage = crVBoxHGSMIHandleNewMessage;
1593 conn->index = g_crvboxhgsmi.num_conns;
1594 conn->sizeof_buffer_header = sizeof(CRVBOXHGSMIBUFFER);
1595 conn->actual_network = 1;
1596
1597 conn->krecv_buf_size = 0;
1598
1599 conn->pBuffer = NULL;
1600 conn->cbBuffer = 0;
1601 conn->allow_redir_ptr = 1;
1602
1603 //@todo remove this crap at all later
1604 conn->cbHostBufferAllocated = 0;//2*1024;
1605 conn->pHostBuffer = NULL;//(uint8_t*) crAlloc(conn->cbHostBufferAllocated);
1606// CRASSERT(conn->pHostBuffer);
1607 conn->cbHostBuffer = 0;
1608
1609 /* Find a free slot */
1610 for (i = 0; i < g_crvboxhgsmi.num_conns; i++) {
1611 if (g_crvboxhgsmi.conns[i] == NULL) {
1612 conn->index = i;
1613 g_crvboxhgsmi.conns[i] = conn;
1614 found = 1;
1615 break;
1616 }
1617 }
1618
1619 /* Realloc connection stack if we couldn't find a free slot */
1620 if (found == 0) {
1621 n_bytes = ( g_crvboxhgsmi.num_conns + 1 ) * sizeof(*g_crvboxhgsmi.conns);
1622 crRealloc( (void **) &g_crvboxhgsmi.conns, n_bytes );
1623 g_crvboxhgsmi.conns[g_crvboxhgsmi.num_conns++] = conn;
1624 }
1625}
1626
1627int crVBoxHGSMIRecv(void)
1628{
1629 int32_t i;
1630 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1631
1632#ifdef IN_GUEST
1633 /* we're on guest side, poll host if it got something for us */
1634 for (i=0; i<g_crvboxhgsmi.num_conns; i++)
1635 {
1636 CRConnection *conn = g_crvboxhgsmi.conns[i];
1637
1638 if ( !conn || conn->type == CR_NO_CONNECTION )
1639 continue;
1640
1641 if (!conn->pBuffer)
1642 {
1643 PCRVBOXHGSMI_CLIENT pClient = _crVBoxHGSMIClientGet();
1644 _crVBoxHGSMIPollHost(conn, pClient);
1645 }
1646 }
1647#endif
1648
1649 for (i=0; i<g_crvboxhgsmi.num_conns; i++)
1650 {
1651 CRConnection *conn = g_crvboxhgsmi.conns[i];
1652
1653 if ( !conn || conn->type == CR_NO_CONNECTION )
1654 continue;
1655
1656 if (conn->cbBuffer>0)
1657 {
1658 PCRVBOXHGSMI_CLIENT pClient = _crVBoxHGSMIClientGet();
1659 _crVBoxHGSMIReceiveMessage(conn, pClient);
1660 }
1661 }
1662
1663 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1664 return 0;
1665}
1666
1667CRConnection** crVBoxHGSMIDump( int *num )
1668{
1669 VBOXCRHGSMIPROFILE_FUNC_PROLOGUE();
1670 Assert(0);
1671 *num = g_crvboxhgsmi.num_conns;
1672
1673 VBOXCRHGSMIPROFILE_FUNC_EPILOGUE();
1674 return g_crvboxhgsmi.conns;
1675}
1676#endif /* #ifdef IN_GUEST */
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