VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use