VirtualBox

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

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

wddm/3d: chromium hgsmi fixes, profiling

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