VirtualBox

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

Last change on this file since 68458 was 68458, checked in by vboxsync, 7 years ago

Introducing macros for initializing the VBoxGuestHGCMCallInfo structure.

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