VirtualBox

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

Last change on this file since 31808 was 30440, checked in by vboxsync, 15 years ago

crOpenGL: wddm friendly windows info tracking + more consistent updates (disabled except windows yet)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 33.6 KB
Line 
1/* $Id: vboxhgcm.c 30440 2010-06-24 18:51:20Z vboxsync $ */
2
3/** @file
4 * VBox HGCM connection
5 */
6
7/*
8 * Copyright (C) 2008 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#ifdef RT_OS_WINDOWS
20 #include <windows.h>
21 #include <ddraw.h>
22#else
23 #include <sys/ioctl.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <unistd.h>
28#endif
29
30#include "cr_error.h"
31#include "cr_net.h"
32#include "cr_bufpool.h"
33#include "cr_mem.h"
34#include "cr_string.h"
35#include "cr_endian.h"
36#include "cr_threads.h"
37#include "net_internals.h"
38
39#if 1 /** @todo Try use the Vbgl interface instead of talking directly to the driver? */
40# include <VBox/VBoxGuest.h>
41#else
42# include <VBox/VBoxGuestLib.h>
43#endif
44#include <VBox/HostServices/VBoxCrOpenGLSvc.h>
45
46typedef struct {
47 int initialized;
48 int num_conns;
49 CRConnection **conns;
50 CRBufferPool *bufpool;
51#ifdef CHROMIUM_THREADSAFE
52 CRmutex mutex;
53 CRmutex recvmutex;
54#endif
55 CRNetReceiveFuncList *recv_list;
56 CRNetCloseFuncList *close_list;
57#ifdef RT_OS_WINDOWS
58 HANDLE hGuestDrv;
59 LPDIRECTDRAW pDirectDraw;
60#else
61 int iGuestDrv;
62#endif
63} CRVBOXHGCMDATA;
64
65static CRVBOXHGCMDATA g_crvboxhgcm = {0,};
66
67typedef enum {
68 CR_VBOXHGCM_USERALLOCATED,
69 CR_VBOXHGCM_MEMORY,
70 CR_VBOXHGCM_MEMORY_BIG
71#ifdef RT_OS_WINDOWS
72 ,CR_VBOXHGCM_DDRAW_SURFACE
73#endif
74} CRVBOXHGCMBUFFERKIND;
75
76#define CR_VBOXHGCM_BUFFER_MAGIC 0xABCDE321
77
78typedef struct CRVBOXHGCMBUFFER {
79 uint32_t magic;
80 CRVBOXHGCMBUFFERKIND kind;
81 uint32_t len;
82 uint32_t allocated;
83#ifdef RT_OS_WINDOWS
84 LPDIRECTDRAWSURFACE pDDS;
85#endif
86} CRVBOXHGCMBUFFER;
87
88#ifndef RT_OS_WINDOWS
89 #define TRUE true
90 #define FALSE false
91 #define INVALID_HANDLE_VALUE (-1)
92#endif
93
94/* Some forward declarations */
95static void crVBoxHGCMReceiveMessage(CRConnection *conn);
96
97#ifndef IN_GUEST
98static bool _crVBoxHGCMReadBytes(CRConnection *conn, void *buf, uint32_t len)
99{
100 CRASSERT(conn && buf);
101
102 if (!conn->pBuffer || (conn->cbBuffer<len))
103 return FALSE;
104
105 crMemcpy(buf, conn->pBuffer, len);
106
107 conn->cbBuffer -= len;
108 conn->pBuffer = conn->cbBuffer>0 ? (uint8_t*)conn->pBuffer+len : NULL;
109
110 return TRUE;
111}
112#endif
113
114/*@todo get rid of it*/
115static bool _crVBoxHGCMWriteBytes(CRConnection *conn, const void *buf, uint32_t len)
116{
117 CRASSERT(conn && buf);
118
119 /* make sure there's host buffer and it's clear */
120 CRASSERT(conn->pHostBuffer && !conn->cbHostBuffer);
121
122 if (conn->cbHostBufferAllocated < len)
123 {
124 crDebug("Host buffer too small %d out of requsted %d bytes, reallocating", conn->cbHostBufferAllocated, len);
125 crFree(conn->pHostBuffer);
126 conn->pHostBuffer = crAlloc(len);
127 if (!conn->pHostBuffer)
128 {
129 conn->cbHostBufferAllocated = 0;
130 crError("OUT_OF_MEMORY trying to allocate %d bytes", len);
131 return FALSE;
132 }
133 conn->cbHostBufferAllocated = len;
134 }
135
136 crMemcpy(conn->pHostBuffer, buf, len);
137 conn->cbHostBuffer = len;
138
139 return TRUE;
140}
141
142/**
143 * Send an HGCM request
144 *
145 * @return VBox status code
146 * @param pvData Data pointer
147 * @param cbData Data size
148 */
149/** @todo use vbglR3DoIOCtl here instead */
150static int crVBoxHGCMCall(void *pvData, unsigned cbData)
151{
152#ifdef IN_GUEST
153
154# ifdef RT_OS_WINDOWS
155 DWORD cbReturned;
156
157 if (DeviceIoControl (g_crvboxhgcm.hGuestDrv,
158 VBOXGUEST_IOCTL_HGCM_CALL(cbData),
159 pvData, cbData,
160 pvData, cbData,
161 &cbReturned,
162 NULL))
163 {
164 return VINF_SUCCESS;
165 }
166 crDebug("vboxCall failed with %x\n", GetLastError());
167 return VERR_NOT_SUPPORTED;
168# else
169 int rc;
170# if defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
171 VBGLBIGREQ Hdr;
172 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
173 Hdr.cbData = cbData;
174 Hdr.pvDataR3 = pvData;
175# if HC_ARCH_BITS == 32
176 Hdr.u32Padding = 0;
177# endif
178 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), &Hdr);
179# else
180 rc = ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CALL(cbData), pvData);
181# endif
182# ifdef RT_OS_LINUX
183 if (rc == 0)
184# else
185 if (rc >= 0)
186# endif
187 {
188 return VINF_SUCCESS;
189 }
190# ifdef RT_OS_LINUX
191 if (rc >= 0) /* positive values are negated VBox error status codes. */
192 crWarning("vboxCall failed with VBox status code %d\n", -rc);
193 else
194# endif
195 crWarning("vboxCall failed with %x\n", errno);
196 return VERR_NOT_SUPPORTED;
197# endif /*#ifdef RT_OS_WINDOWS*/
198
199#else /*#ifdef IN_GUEST*/
200 crError("crVBoxHGCMCall called on host side!");
201 CRASSERT(FALSE);
202 return VERR_NOT_SUPPORTED;
203#endif
204}
205
206static void *crVBoxHGCMAlloc(CRConnection *conn)
207{
208 CRVBOXHGCMBUFFER *buf;
209
210#ifdef CHROMIUM_THREADSAFE
211 crLockMutex(&g_crvboxhgcm.mutex);
212#endif
213
214 buf = (CRVBOXHGCMBUFFER *) crBufferPoolPop(g_crvboxhgcm.bufpool, conn->buffer_size);
215
216 if (!buf)
217 {
218 crDebug("Buffer pool %p was empty; allocating new %d byte buffer.",
219 (void *) g_crvboxhgcm.bufpool,
220 (unsigned int)sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size);
221
222#if defined(IN_GUEST) && defined(RT_OS_WINDOWS)
223 /* Try to start DDRAW on guest side */
224 if (!g_crvboxhgcm.pDirectDraw && 0)
225 {
226 HRESULT hr;
227
228 hr = DirectDrawCreate(NULL, &g_crvboxhgcm.pDirectDraw, NULL);
229 if (hr != DD_OK)
230 {
231 crWarning("Failed to create DirectDraw interface (%x)\n", hr);
232 g_crvboxhgcm.pDirectDraw = NULL;
233 }
234 else
235 {
236 hr = IDirectDraw_SetCooperativeLevel(g_crvboxhgcm.pDirectDraw, NULL, DDSCL_NORMAL);
237 if (hr != DD_OK)
238 {
239 crWarning("Failed to SetCooperativeLevel (%x)\n", hr);
240 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
241 g_crvboxhgcm.pDirectDraw = NULL;
242 }
243 crDebug("Created DirectDraw and set CooperativeLevel successfully\n");
244 }
245 }
246
247 /* Try to allocate buffer via DDRAW */
248 if (g_crvboxhgcm.pDirectDraw)
249 {
250 DDSURFACEDESC ddsd;
251 HRESULT hr;
252 LPDIRECTDRAWSURFACE lpDDS;
253
254 memset(&ddsd, 0, sizeof(ddsd));
255 ddsd.dwSize = sizeof(ddsd);
256
257 /* @todo DDSCAPS_VIDEOMEMORY ain't working for some reason
258 * also, it would be better to request dwLinearSize but it fails too
259 * ddsd.dwLinearSize = sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size;
260 */
261
262 ddsd.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT;
263 ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
264 /* use 1 byte per pixel format */
265 ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
266 ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
267 ddsd.ddpfPixelFormat.dwRGBBitCount = 8;
268 ddsd.ddpfPixelFormat.dwRBitMask = 0xFF;
269 ddsd.ddpfPixelFormat.dwGBitMask = 0;
270 ddsd.ddpfPixelFormat.dwBBitMask = 0;
271 /* request given buffer size, rounded to 1k */
272 ddsd.dwWidth = 1024;
273 ddsd.dwHeight = (sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size + ddsd.dwWidth-1)/ddsd.dwWidth;
274
275 hr = IDirectDraw_CreateSurface(g_crvboxhgcm.pDirectDraw, &ddsd, &lpDDS, NULL);
276 if (hr != DD_OK)
277 {
278 crWarning("Failed to create DirectDraw surface (%x)\n", hr);
279 }
280 else
281 {
282 crDebug("Created DirectDraw surface (%x)\n", lpDDS);
283
284 hr = IDirectDrawSurface_Lock(lpDDS, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR, NULL);
285 if (hr != DD_OK)
286 {
287 crWarning("Failed to lock DirectDraw surface (%x)\n", hr);
288 IDirectDrawSurface_Release(lpDDS);
289 }
290 else
291 {
292 uint32_t cbLocked;
293 cbLocked = (ddsd.dwFlags & DDSD_LINEARSIZE) ? ddsd.dwLinearSize : ddsd.lPitch*ddsd.dwHeight;
294
295 crDebug("Locked %d bytes DirectDraw surface\n", cbLocked);
296
297 buf = (CRVBOXHGCMBUFFER *) ddsd.lpSurface;
298 CRASSERT(buf);
299 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
300 buf->kind = CR_VBOXHGCM_DDRAW_SURFACE;
301 buf->allocated = cbLocked;
302 buf->pDDS = lpDDS;
303 }
304 }
305 }
306#endif
307
308 /* We're either on host side, or we failed to allocate DDRAW buffer */
309 if (!buf)
310 {
311 crDebug("Using system malloc\n");
312 buf = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + conn->buffer_size );
313 CRASSERT(buf);
314 buf->magic = CR_VBOXHGCM_BUFFER_MAGIC;
315 buf->kind = CR_VBOXHGCM_MEMORY;
316 buf->allocated = conn->buffer_size;
317#ifdef RT_OS_WINDOWS
318 buf->pDDS = NULL;
319#endif
320 }
321 }
322
323#ifdef CHROMIUM_THREADSAFE
324 crUnlockMutex(&g_crvboxhgcm.mutex);
325#endif
326
327 return (void *)( buf + 1 );
328
329}
330
331static void crVBoxHGCMWriteExact(CRConnection *conn, const void *buf, unsigned int len)
332{
333 int rc;
334 int32_t callRes;
335
336#ifdef IN_GUEST
337 if (conn->u32InjectClientID)
338 {
339 CRVBOXHGCMINJECT parms;
340
341 parms.hdr.result = VERR_WRONG_ORDER;
342 parms.hdr.u32ClientID = conn->u32ClientID;
343 parms.hdr.u32Function = SHCRGL_GUEST_FN_INJECT;
344 parms.hdr.cParms = SHCRGL_CPARMS_INJECT;
345
346 parms.u32ClientID.type = VMMDevHGCMParmType_32bit;
347 parms.u32ClientID.u.value32 = conn->u32InjectClientID;
348
349 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
350 parms.pBuffer.u.Pointer.size = len;
351 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
352
353 rc = crVBoxHGCMCall(&parms, sizeof(parms));
354 callRes = parms.hdr.result;
355 }
356 else
357#endif
358 {
359 CRVBOXHGCMWRITE parms;
360
361 parms.hdr.result = VERR_WRONG_ORDER;
362 parms.hdr.u32ClientID = conn->u32ClientID;
363 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE;
364 parms.hdr.cParms = SHCRGL_CPARMS_WRITE;
365
366 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
367 parms.pBuffer.u.Pointer.size = len;
368 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
369
370 rc = crVBoxHGCMCall(&parms, sizeof(parms));
371 callRes = parms.hdr.result;
372 }
373
374 if (RT_FAILURE(rc) || RT_FAILURE(callRes))
375 {
376 crWarning("SHCRGL_GUEST_FN_WRITE failed with %x %x\n", rc, callRes);
377 }
378}
379
380static void crVBoxHGCMReadExact( CRConnection *conn, const void *buf, unsigned int len )
381{
382 CRVBOXHGCMREAD parms;
383 int rc;
384
385 parms.hdr.result = VERR_WRONG_ORDER;
386 parms.hdr.u32ClientID = conn->u32ClientID;
387 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
388 parms.hdr.cParms = SHCRGL_CPARMS_READ;
389
390 CRASSERT(!conn->pBuffer); //make sure there's no data to process
391 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
392 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
393 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
394
395 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
396 parms.cbBuffer.u.value32 = 0;
397
398 rc = crVBoxHGCMCall(&parms, sizeof(parms));
399
400 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
401 {
402 crWarning("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
403 return;
404 }
405
406 if (parms.cbBuffer.u.value32)
407 {
408 //conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
409 conn->pBuffer = conn->pHostBuffer;
410 conn->cbBuffer = parms.cbBuffer.u.value32;
411 }
412
413 if (conn->cbBuffer)
414 crVBoxHGCMReceiveMessage(conn);
415
416}
417
418/* Same as crVBoxHGCMWriteExact, but combined with read of writeback data.
419 * This halves the number of HGCM calls we do,
420 * most likely crVBoxHGCMPollHost shouldn't be called at all now.
421 */
422static void
423crVBoxHGCMWriteReadExact(CRConnection *conn, const void *buf, unsigned int len, CRVBOXHGCMBUFFERKIND bufferKind)
424{
425 CRVBOXHGCMWRITEREAD parms;
426 int rc;
427
428 parms.hdr.result = VERR_WRONG_ORDER;
429 parms.hdr.u32ClientID = conn->u32ClientID;
430 parms.hdr.u32Function = SHCRGL_GUEST_FN_WRITE_READ;
431 parms.hdr.cParms = SHCRGL_CPARMS_WRITE_READ;
432
433 //if (bufferKind != CR_VBOXHGCM_DDRAW_SURFACE)
434 {
435 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_In;
436 parms.pBuffer.u.Pointer.size = len;
437 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) buf;
438 }
439 /*else ///@todo it fails badly, have to check why. bird: This fails because buf isn't a physical address?
440 {
441 parms.pBuffer.type = VMMDevHGCMParmType_PhysAddr;
442 parms.pBuffer.u.Pointer.size = len;
443 parms.pBuffer.u.Pointer.u.physAddr = (uintptr_t) buf;
444 }*/
445
446 CRASSERT(!conn->pBuffer); //make sure there's no data to process
447 parms.pWriteback.type = VMMDevHGCMParmType_LinAddr_Out;
448 parms.pWriteback.u.Pointer.size = conn->cbHostBufferAllocated;
449 parms.pWriteback.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
450
451 parms.cbWriteback.type = VMMDevHGCMParmType_32bit;
452 parms.cbWriteback.u.value32 = 0;
453
454 rc = crVBoxHGCMCall(&parms, sizeof(parms));
455
456 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
457 {
458
459 if ((VERR_BUFFER_OVERFLOW == parms.hdr.result) && RT_SUCCESS(rc))
460 {
461 /* reallocate buffer and retry */
462
463 CRASSERT(parms.cbWriteback.u.value32>conn->cbHostBufferAllocated);
464
465 crDebug("Reallocating host buffer from %d to %d bytes", conn->cbHostBufferAllocated, parms.cbWriteback.u.value32);
466
467 crFree(conn->pHostBuffer);
468 conn->cbHostBufferAllocated = parms.cbWriteback.u.value32;
469 conn->pHostBuffer = crAlloc(conn->cbHostBufferAllocated);
470
471 crVBoxHGCMReadExact(conn, buf, len);
472
473 return;
474 }
475 else
476 {
477 crWarning("SHCRGL_GUEST_FN_WRITE_READ (%i) failed with %x %x\n", len, rc, parms.hdr.result);
478 return;
479 }
480 }
481
482 if (parms.cbWriteback.u.value32)
483 {
484 //conn->pBuffer = (uint8_t*) parms.pWriteback.u.Pointer.u.linearAddr;
485 conn->pBuffer = conn->pHostBuffer;
486 conn->cbBuffer = parms.cbWriteback.u.value32;
487 }
488
489 if (conn->cbBuffer)
490 crVBoxHGCMReceiveMessage(conn);
491}
492
493static void crVBoxHGCMSend(CRConnection *conn, void **bufp,
494 const void *start, unsigned int len)
495{
496 CRVBOXHGCMBUFFER *hgcm_buffer;
497
498 if (!bufp) /* We're sending a user-allocated buffer. */
499 {
500#ifndef IN_GUEST
501 //@todo remove temp buffer allocation in unpacker
502 /* we're at the host side, so just store data until guest polls us */
503 _crVBoxHGCMWriteBytes(conn, start, len);
504#else
505 CRASSERT(!conn->u32InjectClientID);
506 crDebug("SHCRGL: sending userbuf with %d bytes\n", len);
507 crVBoxHGCMWriteReadExact(conn, start, len, CR_VBOXHGCM_USERALLOCATED);
508#endif
509 return;
510 }
511
512 /* The region [start .. start + len + 1] lies within a buffer that
513 * was allocated with crVBoxHGCMAlloc() and can be put into the free
514 * buffer pool when we're done sending it.
515 */
516
517 hgcm_buffer = (CRVBOXHGCMBUFFER *)(*bufp) - 1;
518 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
519
520 /* Length would be passed as part of HGCM pointer description
521 * No need to prepend it to the buffer
522 */
523#ifdef IN_GUEST
524 if (conn->u32InjectClientID)
525 {
526 crVBoxHGCMWriteExact(conn, start, len);
527 }
528 else
529#endif
530 crVBoxHGCMWriteReadExact(conn, start, len, hgcm_buffer->kind);
531
532 /* Reclaim this pointer for reuse */
533#ifdef CHROMIUM_THREADSAFE
534 crLockMutex(&g_crvboxhgcm.mutex);
535#endif
536 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
537#ifdef CHROMIUM_THREADSAFE
538 crUnlockMutex(&g_crvboxhgcm.mutex);
539#endif
540
541 /* Since the buffer's now in the 'free' buffer pool, the caller can't
542 * use it any more. Setting bufp to NULL will make sure the caller
543 * doesn't try to re-use the buffer.
544 */
545 *bufp = NULL;
546}
547
548static void crVBoxHGCMPollHost(CRConnection *conn)
549{
550 CRVBOXHGCMREAD parms;
551 int rc;
552
553 CRASSERT(!conn->pBuffer);
554
555 parms.hdr.result = VERR_WRONG_ORDER;
556 parms.hdr.u32ClientID = conn->u32ClientID;
557 parms.hdr.u32Function = SHCRGL_GUEST_FN_READ;
558 parms.hdr.cParms = SHCRGL_CPARMS_READ;
559
560 parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out;
561 parms.pBuffer.u.Pointer.size = conn->cbHostBufferAllocated;
562 parms.pBuffer.u.Pointer.u.linearAddr = (uintptr_t) conn->pHostBuffer;
563
564 parms.cbBuffer.type = VMMDevHGCMParmType_32bit;
565 parms.cbBuffer.u.value32 = 0;
566
567 rc = crVBoxHGCMCall(&parms, sizeof(parms));
568
569 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
570 {
571 crDebug("SHCRGL_GUEST_FN_READ failed with %x %x\n", rc, parms.hdr.result);
572 return;
573 }
574
575 if (parms.cbBuffer.u.value32)
576 {
577 conn->pBuffer = (uint8_t*) parms.pBuffer.u.Pointer.u.linearAddr;
578 conn->cbBuffer = parms.cbBuffer.u.value32;
579 }
580}
581
582static void crVBoxHGCMSingleRecv(CRConnection *conn, void *buf, unsigned int len)
583{
584 crVBoxHGCMReadExact(conn, buf, len);
585}
586
587static void crVBoxHGCMFree(CRConnection *conn, void *buf)
588{
589 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) buf - 1;
590
591 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
592
593 /*@todo wrong len for redir buffers*/
594 conn->recv_credits += hgcm_buffer->len;
595
596 switch (hgcm_buffer->kind)
597 {
598 case CR_VBOXHGCM_MEMORY:
599#ifdef RT_OS_WINDOWS
600 case CR_VBOXHGCM_DDRAW_SURFACE:
601#endif
602#ifdef CHROMIUM_THREADSAFE
603 crLockMutex(&g_crvboxhgcm.mutex);
604#endif
605 if (g_crvboxhgcm.bufpool) {
606 //@todo o'rly?
607 /* pool may have been deallocated just a bit earlier in response
608 * to a SIGPIPE (Broken Pipe) signal.
609 */
610 crBufferPoolPush(g_crvboxhgcm.bufpool, hgcm_buffer, hgcm_buffer->allocated);
611 }
612#ifdef CHROMIUM_THREADSAFE
613 crUnlockMutex(&g_crvboxhgcm.mutex);
614#endif
615 break;
616
617 case CR_VBOXHGCM_MEMORY_BIG:
618 crFree( hgcm_buffer );
619 break;
620
621 default:
622 crError( "Weird buffer kind trying to free in crVBoxHGCMFree: %d", hgcm_buffer->kind );
623 }
624}
625
626static void crVBoxHGCMReceiveMessage(CRConnection *conn)
627{
628 uint32_t len;
629 CRVBOXHGCMBUFFER *hgcm_buffer;
630 CRMessage *msg;
631 CRMessageType cached_type;
632
633 len = conn->cbBuffer;
634 CRASSERT(len > 0);
635 CRASSERT(conn->pBuffer);
636
637#ifndef IN_GUEST
638 if (conn->allow_redir_ptr)
639 {
640#endif //IN_GUEST
641 CRASSERT(conn->buffer_size >= sizeof(CRMessageRedirPtr));
642
643 hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
644 hgcm_buffer->len = sizeof(CRMessageRedirPtr);
645
646 msg = (CRMessage *) (hgcm_buffer + 1);
647
648 msg->header.type = CR_MESSAGE_REDIR_PTR;
649 msg->redirptr.pMessage = (CRMessageHeader*) (conn->pBuffer);
650 msg->header.conn_id = msg->redirptr.pMessage->conn_id;
651
652 cached_type = msg->redirptr.pMessage->type;
653
654 conn->cbBuffer = 0;
655 conn->pBuffer = NULL;
656#ifndef IN_GUEST
657 }
658 else
659 {
660 if ( len <= conn->buffer_size )
661 {
662 /* put in pre-allocated buffer */
663 hgcm_buffer = (CRVBOXHGCMBUFFER *) crVBoxHGCMAlloc( conn ) - 1;
664 }
665 else
666 {
667 /* allocate new buffer,
668 * not using pool here as it's most likely one time transfer of huge texture
669 */
670 hgcm_buffer = (CRVBOXHGCMBUFFER *) crAlloc( sizeof(CRVBOXHGCMBUFFER) + len );
671 hgcm_buffer->magic = CR_VBOXHGCM_BUFFER_MAGIC;
672 hgcm_buffer->kind = CR_VBOXHGCM_MEMORY_BIG;
673 hgcm_buffer->allocated = sizeof(CRVBOXHGCMBUFFER) + len;
674# ifdef RT_OS_WINDOWS
675 hgcm_buffer->pDDS = NULL;
676# endif
677 }
678
679 hgcm_buffer->len = len;
680
681 _crVBoxHGCMReadBytes(conn, hgcm_buffer + 1, len);
682
683 msg = (CRMessage *) (hgcm_buffer + 1);
684 cached_type = msg->header.type;
685 }
686#endif //IN_GUEST
687
688 conn->recv_credits -= len;
689 conn->total_bytes_recv += len;
690
691 crNetDispatchMessage( g_crvboxhgcm.recv_list, conn, msg, len );
692
693 /* CR_MESSAGE_OPCODES is freed in crserverlib/server_stream.c with crNetFree.
694 * OOB messages are the programmer's problem. -- Humper 12/17/01
695 */
696 if (cached_type != CR_MESSAGE_OPCODES
697 && cached_type != CR_MESSAGE_OOB
698 && cached_type != CR_MESSAGE_GATHER)
699 {
700 crVBoxHGCMFree(conn, msg);
701 }
702}
703
704/*
705 * Called on host side only, to "accept" client connection
706 */
707static void crVBoxHGCMAccept( CRConnection *conn, const char *hostname, unsigned short port )
708{
709 CRASSERT(conn && conn->pHostBuffer);
710#ifdef IN_GUEST
711 CRASSERT(FALSE);
712#endif
713}
714
715static int crVBoxHGCMSetVersion(CRConnection *conn, unsigned int vMajor, unsigned int vMinor)
716{
717 CRVBOXHGCMSETVERSION parms;
718 int rc;
719
720 parms.hdr.result = VERR_WRONG_ORDER;
721 parms.hdr.u32ClientID = conn->u32ClientID;
722 parms.hdr.u32Function = SHCRGL_GUEST_FN_SET_VERSION;
723 parms.hdr.cParms = SHCRGL_CPARMS_SET_VERSION;
724
725 parms.vMajor.type = VMMDevHGCMParmType_32bit;
726 parms.vMajor.u.value32 = CR_PROTOCOL_VERSION_MAJOR;
727 parms.vMinor.type = VMMDevHGCMParmType_32bit;
728 parms.vMinor.u.value32 = CR_PROTOCOL_VERSION_MINOR;
729
730 rc = crVBoxHGCMCall(&parms, sizeof(parms));
731
732 if (RT_FAILURE(rc) || RT_FAILURE(parms.hdr.result))
733 {
734 crWarning("Host doesn't accept our version %d.%d. Make sure you have appropriate additions installed!",
735 parms.vMajor.u.value32, parms.vMinor.u.value32);
736 return FALSE;
737 }
738
739 conn->vMajor = CR_PROTOCOL_VERSION_MAJOR;
740 conn->vMinor = CR_PROTOCOL_VERSION_MINOR;
741
742 return TRUE;
743}
744
745/**
746 * The function that actually connects. This should only be called by clients,
747 * guests in vbox case.
748 * Servers go through crVBoxHGCMAccept;
749 */
750/*@todo use vbglR3Something here */
751static int crVBoxHGCMDoConnect( CRConnection *conn )
752{
753#ifdef IN_GUEST
754 VBoxGuestHGCMConnectInfo info;
755
756#ifdef RT_OS_WINDOWS
757 DWORD cbReturned;
758
759 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
760 {
761 /* open VBox guest driver */
762 g_crvboxhgcm.hGuestDrv = CreateFile(VBOXGUEST_DEVICE_NAME,
763 GENERIC_READ | GENERIC_WRITE,
764 FILE_SHARE_READ | FILE_SHARE_WRITE,
765 NULL,
766 OPEN_EXISTING,
767 FILE_ATTRIBUTE_NORMAL,
768 NULL);
769
770 /* @todo check if we could rollback to softwareopengl */
771 if (g_crvboxhgcm.hGuestDrv == INVALID_HANDLE_VALUE)
772 {
773 crDebug("could not open VBox Guest Additions driver! rc = %d\n", GetLastError());
774 return FALSE;
775 }
776 }
777#else
778 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
779 {
780 g_crvboxhgcm.iGuestDrv = open(VBOXGUEST_USER_DEVICE_NAME, O_RDWR, 0);
781 if (g_crvboxhgcm.iGuestDrv == INVALID_HANDLE_VALUE)
782 {
783 crDebug("could not open Guest Additions kernel module! rc = %d\n", errno);
784 return FALSE;
785 }
786 }
787#endif
788
789 memset (&info, 0, sizeof (info));
790 info.Loc.type = VMMDevHGCMLoc_LocalHost_Existing;
791 strcpy (info.Loc.u.host.achName, "VBoxSharedCrOpenGL");
792
793#ifdef RT_OS_WINDOWS
794 if (DeviceIoControl(g_crvboxhgcm.hGuestDrv,
795 VBOXGUEST_IOCTL_HGCM_CONNECT,
796 &info, sizeof (info),
797 &info, sizeof (info),
798 &cbReturned,
799 NULL))
800#elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
801 VBGLBIGREQ Hdr;
802 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
803 Hdr.cbData = sizeof(info);
804 Hdr.pvDataR3 = &info;
805# if HC_ARCH_BITS == 32
806 Hdr.u32Padding = 0;
807# endif
808 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &Hdr) >= 0)
809#else
810 /*@todo it'd fail */
811 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_CONNECT, &info, sizeof (info)) >= 0)
812#endif
813 {
814 if (info.result == VINF_SUCCESS)
815 {
816 conn->u32ClientID = info.u32ClientID;
817 crDebug("HGCM connect was successful: client id =0x%x\n", conn->u32ClientID);
818
819 return crVBoxHGCMSetVersion(conn, CR_PROTOCOL_VERSION_MAJOR, CR_PROTOCOL_VERSION_MINOR);
820 }
821 else
822 {
823 crDebug("HGCM connect failed with rc=0x%x\n", info.result);
824 return FALSE;
825 }
826 }
827 else
828 {
829#ifdef RT_OS_WINDOWS
830 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", GetLastError());
831#else
832 crDebug("IOCTL for HGCM connect failed with rc=0x%x\n", errno);
833#endif
834 return FALSE;
835 }
836
837 return TRUE;
838
839#else /*#ifdef IN_GUEST*/
840 crError("crVBoxHGCMDoConnect called on host side!");
841 CRASSERT(FALSE);
842 return FALSE;
843#endif
844}
845
846/*@todo same, replace DeviceIoControl with vbglR3DoIOCtl */
847static void crVBoxHGCMDoDisconnect( CRConnection *conn )
848{
849#ifdef IN_GUEST
850 VBoxGuestHGCMDisconnectInfo info;
851# ifdef RT_OS_WINDOWS
852 DWORD cbReturned;
853# endif
854 int i;
855#endif
856
857 if (conn->pHostBuffer)
858 {
859 crFree(conn->pHostBuffer);
860 conn->pHostBuffer = NULL;
861 conn->cbHostBuffer = 0;
862 conn->cbHostBufferAllocated = 0;
863 }
864
865 conn->pBuffer = NULL;
866 conn->cbBuffer = 0;
867
868 //@todo hold lock here?
869 if (conn->type == CR_VBOXHGCM)
870 {
871 --g_crvboxhgcm.num_conns;
872
873 if (conn->index < g_crvboxhgcm.num_conns)
874 {
875 g_crvboxhgcm.conns[conn->index] = g_crvboxhgcm.conns[g_crvboxhgcm.num_conns];
876 g_crvboxhgcm.conns[conn->index]->index = conn->index;
877 }
878 else g_crvboxhgcm.conns[conn->index] = NULL;
879
880 conn->type = CR_NO_CONNECTION;
881 }
882
883#ifndef IN_GUEST
884#else /* IN_GUEST */
885 if (conn->u32ClientID)
886 {
887 memset (&info, 0, sizeof (info));
888 info.u32ClientID = conn->u32ClientID;
889
890# ifdef RT_OS_WINDOWS
891 if ( !DeviceIoControl(g_crvboxhgcm.hGuestDrv,
892 VBOXGUEST_IOCTL_HGCM_DISCONNECT,
893 &info, sizeof (info),
894 &info, sizeof (info),
895 &cbReturned,
896 NULL) )
897 {
898 crDebug("Disconnect failed with %x\n", GetLastError());
899 }
900# elif defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
901 VBGLBIGREQ Hdr;
902 Hdr.u32Magic = VBGLBIGREQ_MAGIC;
903 Hdr.cbData = sizeof(info);
904 Hdr.pvDataR3 = &info;
905# if HC_ARCH_BITS == 32
906 Hdr.u32Padding = 0;
907# endif
908 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &Hdr) >= 0)
909# else
910 if (ioctl(g_crvboxhgcm.iGuestDrv, VBOXGUEST_IOCTL_HGCM_DISCONNECT, &info, sizeof (info)) < 0)
911 {
912 crDebug("Disconnect failed with %x\n", errno);
913 }
914# endif
915
916 conn->u32ClientID = 0;
917 }
918
919 /* see if any connections remain */
920 for (i = 0; i < g_crvboxhgcm.num_conns; i++)
921 if (g_crvboxhgcm.conns[i] && g_crvboxhgcm.conns[i]->type != CR_NO_CONNECTION)
922 break;
923
924 /* close guest additions driver*/
925 if (i>=g_crvboxhgcm.num_conns)
926 {
927# ifdef RT_OS_WINDOWS
928 CloseHandle(g_crvboxhgcm.hGuestDrv);
929 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
930# else
931 close(g_crvboxhgcm.iGuestDrv);
932 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
933# endif
934 }
935#endif /* IN_GUEST */
936}
937
938static void crVBoxHGCMInstantReclaim(CRConnection *conn, CRMessage *mess)
939{
940 crVBoxHGCMFree(conn, mess);
941 CRASSERT(FALSE);
942}
943
944static void crVBoxHGCMHandleNewMessage( CRConnection *conn, CRMessage *msg, unsigned int len )
945{
946 CRASSERT(FALSE);
947}
948
949void crVBoxHGCMInit(CRNetReceiveFuncList *rfl, CRNetCloseFuncList *cfl, unsigned int mtu)
950{
951 (void) mtu;
952
953 g_crvboxhgcm.recv_list = rfl;
954 g_crvboxhgcm.close_list = cfl;
955 if (g_crvboxhgcm.initialized)
956 {
957 return;
958 }
959
960 g_crvboxhgcm.initialized = 1;
961
962 g_crvboxhgcm.num_conns = 0;
963 g_crvboxhgcm.conns = NULL;
964
965 /* Can't open VBox guest driver here, because it gets called for host side as well */
966 /*@todo as we have 2 dll versions, can do it now.*/
967
968#ifdef RT_OS_WINDOWS
969 g_crvboxhgcm.hGuestDrv = INVALID_HANDLE_VALUE;
970 g_crvboxhgcm.pDirectDraw = NULL;
971#else
972 g_crvboxhgcm.iGuestDrv = INVALID_HANDLE_VALUE;
973#endif
974
975#ifdef CHROMIUM_THREADSAFE
976 crInitMutex(&g_crvboxhgcm.mutex);
977 crInitMutex(&g_crvboxhgcm.recvmutex);
978#endif
979 g_crvboxhgcm.bufpool = crBufferPoolInit(16);
980}
981
982/* Callback function used to free buffer pool entries */
983void crVBoxHGCMBufferFree(void *data)
984{
985#ifdef RT_OS_WINDOWS
986 LPDIRECTDRAWSURFACE lpDDS;
987#endif
988 CRVBOXHGCMBUFFER *hgcm_buffer = (CRVBOXHGCMBUFFER *) data;
989
990 CRASSERT(hgcm_buffer->magic == CR_VBOXHGCM_BUFFER_MAGIC);
991
992 switch (hgcm_buffer->kind)
993 {
994 case CR_VBOXHGCM_MEMORY:
995 crFree( hgcm_buffer );
996 break;
997#ifdef RT_OS_WINDOWS
998 case CR_VBOXHGCM_DDRAW_SURFACE:
999 lpDDS = hgcm_buffer->pDDS;
1000 CRASSERT(lpDDS);
1001 IDirectDrawSurface_Unlock(lpDDS, NULL);
1002 IDirectDrawSurface_Release(lpDDS);
1003 crDebug("DDraw surface freed (%x)\n", lpDDS);
1004 break;
1005#endif
1006 case CR_VBOXHGCM_MEMORY_BIG:
1007 crFree( hgcm_buffer );
1008 break;
1009
1010 default:
1011 crError( "Weird buffer kind trying to free in crVBoxHGCMBufferFree: %d", hgcm_buffer->kind );
1012 }
1013}
1014
1015void crVBoxHGCMTearDown(void)
1016{
1017 int32_t i, cCons;
1018
1019 if (!g_crvboxhgcm.initialized) return;
1020
1021 /* Connection count would be changed in calls to crNetDisconnect, so we have to store original value.
1022 * Walking array backwards is not a good idea as it could cause some issues if we'd disconnect clients not in the
1023 * order of their connection.
1024 */
1025 cCons = g_crvboxhgcm.num_conns;
1026 for (i=0; i<cCons; i++)
1027 {
1028 /* Note that [0] is intended, as the connections array would be shifted in each call to crNetDisconnect */
1029 crNetDisconnect(g_crvboxhgcm.conns[0]);
1030 }
1031 CRASSERT(0==g_crvboxhgcm.num_conns);
1032
1033#ifdef CHROMIUM_THREADSAFE
1034 crFreeMutex(&g_crvboxhgcm.mutex);
1035 crFreeMutex(&g_crvboxhgcm.recvmutex);
1036#endif
1037
1038 if (g_crvboxhgcm.bufpool)
1039 crBufferPoolCallbackFree(g_crvboxhgcm.bufpool, crVBoxHGCMBufferFree);
1040 g_crvboxhgcm.bufpool = NULL;
1041
1042 g_crvboxhgcm.initialized = 0;
1043
1044 crFree(g_crvboxhgcm.conns);
1045 g_crvboxhgcm.conns = NULL;
1046
1047#ifdef RT_OS_WINDOWS
1048 if (g_crvboxhgcm.pDirectDraw)
1049 {
1050 IDirectDraw_Release(g_crvboxhgcm.pDirectDraw);
1051 g_crvboxhgcm.pDirectDraw = NULL;
1052 crDebug("DirectDraw released\n");
1053 }
1054#endif
1055}
1056
1057void crVBoxHGCMConnection(CRConnection *conn)
1058{
1059 int i, found = 0;
1060 int n_bytes;
1061
1062 CRASSERT(g_crvboxhgcm.initialized);
1063
1064 conn->type = CR_VBOXHGCM;
1065 conn->Alloc = crVBoxHGCMAlloc;
1066 conn->Send = crVBoxHGCMSend;
1067 conn->SendExact = crVBoxHGCMWriteExact;
1068 conn->Recv = crVBoxHGCMSingleRecv;
1069 conn->RecvMsg = crVBoxHGCMReceiveMessage;
1070 conn->Free = crVBoxHGCMFree;
1071 conn->Accept = crVBoxHGCMAccept;
1072 conn->Connect = crVBoxHGCMDoConnect;
1073 conn->Disconnect = crVBoxHGCMDoDisconnect;
1074 conn->InstantReclaim = crVBoxHGCMInstantReclaim;
1075 conn->HandleNewMessage = crVBoxHGCMHandleNewMessage;
1076 conn->index = g_crvboxhgcm.num_conns;
1077 conn->sizeof_buffer_header = sizeof(CRVBOXHGCMBUFFER);
1078 conn->actual_network = 1;
1079
1080 conn->krecv_buf_size = 0;
1081
1082 conn->pBuffer = NULL;
1083 conn->cbBuffer = 0;
1084 conn->allow_redir_ptr = 1;
1085
1086 //@todo remove this crap at all later
1087 conn->cbHostBufferAllocated = 2*1024;
1088 conn->pHostBuffer = (uint8_t*) crAlloc(conn->cbHostBufferAllocated);
1089 CRASSERT(conn->pHostBuffer);
1090 conn->cbHostBuffer = 0;
1091
1092 /* Find a free slot */
1093 for (i = 0; i < g_crvboxhgcm.num_conns; i++) {
1094 if (g_crvboxhgcm.conns[i] == NULL) {
1095 conn->index = i;
1096 g_crvboxhgcm.conns[i] = conn;
1097 found = 1;
1098 break;
1099 }
1100 }
1101
1102 /* Realloc connection stack if we couldn't find a free slot */
1103 if (found == 0) {
1104 n_bytes = ( g_crvboxhgcm.num_conns + 1 ) * sizeof(*g_crvboxhgcm.conns);
1105 crRealloc( (void **) &g_crvboxhgcm.conns, n_bytes );
1106 g_crvboxhgcm.conns[g_crvboxhgcm.num_conns++] = conn;
1107 }
1108}
1109
1110int crVBoxHGCMRecv(void)
1111{
1112 int32_t i;
1113
1114#ifdef IN_GUEST
1115 /* we're on guest side, poll host if it got something for us */
1116 for (i=0; i<g_crvboxhgcm.num_conns; i++)
1117 {
1118 CRConnection *conn = g_crvboxhgcm.conns[i];
1119
1120 if ( !conn || conn->type == CR_NO_CONNECTION )
1121 continue;
1122
1123 if (!conn->pBuffer)
1124 {
1125 crVBoxHGCMPollHost(conn);
1126 }
1127 }
1128#endif
1129
1130 for (i=0; i<g_crvboxhgcm.num_conns; i++)
1131 {
1132 CRConnection *conn = g_crvboxhgcm.conns[i];
1133
1134 if ( !conn || conn->type == CR_NO_CONNECTION )
1135 continue;
1136
1137 if (conn->cbBuffer>0)
1138 {
1139 crVBoxHGCMReceiveMessage(conn);
1140 }
1141 }
1142
1143 return 0;
1144}
1145
1146CRConnection** crVBoxHGCMDump( int *num )
1147{
1148 *num = g_crvboxhgcm.num_conns;
1149
1150 return g_crvboxhgcm.conns;
1151}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette