VirtualBox

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

Last change on this file since 18508 was 18508, checked in by vboxsync, 16 years ago

crVBoxHGCMDoDisconnect: unused variable warnings (host).

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