VirtualBox

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

Last change on this file since 32909 was 32909, checked in by vboxsync, 14 years ago

crOpenGL: add mbps/cps to fps measurement

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