VirtualBox

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

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

VBoxGuest.h/VMMDev.h/VBoxGuestLib.h usage cleanup.

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