VirtualBox

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

Last change on this file since 24107 was 21776, checked in by vboxsync, 15 years ago

ogl/vboxhgcm.c: adjust ioctl return code check for linux, init the HGCM call result with a failure instead of success (in case it isn't copied back to ring-3).

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