VirtualBox

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

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

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use