fakedri_drv.c revision bf27e60c824d1a47711ba0a4437451ad51c4a4ec
/* $Id$ */
/** @file
* VBox OpenGL DRI driver functions
*/
/*
* Copyright (C) 2009 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#define _GNU_SOURCE 1
#include "cr_error.h"
#include "cr_gl.h"
#include "cr_mem.h"
#include "stub.h"
#include "fakedri_drv.h"
#include "dri_glx.h"
#include <dlfcn.h>
#include <elf.h>
#include <unistd.h>
/** X server message type definitions. */
typedef enum {
X_PROBED, /* Value was probed */
X_CONFIG, /* Value was given in the config file */
X_DEFAULT, /* Value is a default */
X_CMDLINE, /* Value was given on the command line */
X_NOTICE, /* Notice */
X_ERROR, /* Error message */
X_WARNING, /* Warning message */
X_INFO, /* Informational message */
X_NONE, /* No prefix */
X_NOT_IMPLEMENTED, /* Not implemented */
} MessageType;
#define VBOX_NO_MESA_PATCH_REPORTS
//#define DEBUG_DRI_CALLS
//@todo this could be different...
#ifdef RT_ARCH_AMD64
#else
# define DRI_DEFAULT_DRIVER_DIR "/usr/lib/dri:/usr/lib/i386-linux-gnu/dri"
#endif
#ifdef DEBUG_DRI_CALLS
#else
#endif
} else { \
}
} else { \
return 0; \
}
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
#ifdef RT_ARCH_AMD64
# define DRI_ELFSYM Elf64_Sym
#else
# define DRI_ELFSYM Elf32_Sym
#endif
#ifdef RT_ARCH_AMD64
typedef struct _FAKEDRI_PatchNode
{
const char* psFuncName;
struct _FAKEDRI_PatchNode *pNext;
#endif
extern const __DRIextension * __driDriverExtensions[];
static void
static void
{
void *pGLTable;
pGLTable = (void *)_glapi_get_dispatch();
if (!vbox_glapi_table)
{
crError("Not enough memory to allocate dispatch table");
}
#include "fakedri_glfuncsList.h"
};
static void
{
#include "fakedri_glxfuncsList.h"
}
static void
{
void *alPatch;
int rv;
/* Get aligned start address we're going to patch*/
#ifndef VBOX_NO_MESA_PATCH_REPORTS
#endif
/* Get write access to mesa functions */
if (RT_FAILURE(rv))
{
}
#ifndef VBOX_NO_MESA_PATCH_REPORTS
#endif
/*@todo Restore the protection, probably have to check what was it before us...*/
if (RT_FAILURE(rv))
{
}
}
#define FAKEDRI_JMP64_PATCH_SIZE 13
static void
{
DRI_ELFSYM* sym=0;
int rv;
void *alPatch;
void *pMesaEntry;
char patch[FAKEDRI_JMP64_PATCH_SIZE];
void *shift;
int ignore_size=false;
#ifndef VBOX_NO_MESA_PATCH_REPORTS
#endif
if (!pMesaEntry)
{
return;
}
{
return;
}
{
DRI_ELFSYM* sym1=0;
int rv;
{
return;
}
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("VBox Entry: %p, start: %p(%s:%s), size: %li", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
# endif
}
#endif
#ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %li", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
#endif
#ifndef VBOX_OGL_GLX_USE_CSTUBS
#endif
{
#ifdef RT_ARCH_AMD64
#endif
{
/*@todo we don't really know the size of targeted static function, but it's long enough in practice. We will also patch same place twice, but it's ok.*/
{
{
/*it's a rel8 jmp, so we're going to patch the place it targets instead of jmp itself*/
ignore_size = true;
}
else
{
return;
}
}
{
/*@todo it's just a return 0, which we're fine with for now*/
return;
}
else
{
return;
}
}
#ifdef RT_ARCH_AMD64
{
/*try to insert 64bit abs jmp*/
{
# ifndef VBOX_NO_MESA_PATCH_REPORTS
# endif
/*add 64bit abs jmp*/
}
else
{
# ifndef VBOX_NO_MESA_PATCH_REPORTS
# endif
/*Add patch node to repatch with chain jmps in 2nd pass*/
if (!pNode)
{
crError("Not enough memory.");
return;
}
return;
}
}
else
#endif
{
#ifndef VBOX_NO_MESA_PATCH_REPORTS
#endif
patch[0] = 0xE9;
}
}
#ifdef RT_ARCH_AMD64
/*Add rest of mesa function body to free list*/
{
if (pNode)
{
g_pFreeList = pNode;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Added free node %s, func start=%p, free start=%p, size=%#lx",
# endif
}
}
#endif
}
#ifdef RT_ARCH_AMD64
static void
vboxRepatchMesaExports(void)
{
char patch[FAKEDRI_JMP64_PATCH_SIZE];
while (pPatchNode)
{
# ifndef VBOX_NO_MESA_PATCH_REPORTS
# endif
/*find free place in mesa functions, to place 64bit jump to our stub code*/
while (pFreeNode)
{
{
{
break;
}
}
}
if (!pFreeNode)
{
return;
}
/*add 32bit rel jmp, from mesa orginal function to free space in other mesa function*/
patch[0] = 0xE9;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
# endif
/*add 64bit abs jmp, from free space to our stub code*/
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Adding jmp from mesa %s+%#lx to vbox %s", pFreeNode->psFuncName, pFreeNode->pDstStart-pFreeNode->pSrcStart,
# endif
/*mark this space as used*/
}
}
static void
{
while (pList)
{
}
}
#endif
#ifdef VBOX_OGL_GLX_USE_CSTUBS
static void
#else
static void
# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, &vbox_glX##Func##_EndProc);
#endif
{
crDebug("Patching mesa glx entries");
#include "fakedri_glxfuncsList.h"
#ifdef RT_ARCH_AMD64
g_pFreeList = NULL;
#endif
}
bool vbox_load_sw_dri()
{
char realDriverName[200];
void *handle;
int len, i;
/*code from Mesa-7.2/src/glx/x11/dri_common.c:driOpenDriver*/
/* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
if (!libPaths)
}
{
{
}
else
{
next++;
}
if (handle) break;
}
/*end code*/
if (!gppSwDriExternsion)
{
return false;
}
for (i = 0; gppSwDriExternsion[i]; i++)
{
}
return gpSwDriCoreExternsion && gpSwDriSwrastExtension;
}
{
{
#ifdef _X_ATTRIBUTE_PRINTF
#else
#endif
if (pxf86Msg)
{
/* we're failing to proxy software dri driver calls for certain xservers, so just make sure we're unloaded for now */
__driDriverExtensions[0] = NULL;
return;
}
}
if (!stubInit())
{
crDebug("vboxdriInitScreen: stubInit failed");
return;
}
/* Load swrast_dri.so to proxy dri related calls there. */
if (!vbox_load_sw_dri())
{
crDebug("vboxdriInitScreen: vbox_load_sw_dri failed...going to fail badly");
return;
}
/* Handle gl api.
* In the end application call would look like this:
* app call glFoo->(mesa asm dispatch stub)->cr_glFoo(vbox asm dispatch stub)->SPU Foo function(packspuFoo or alike)
* Note, we don't need to install extension functions via _glapi_add_dispatch, because we'd override glXGetProcAddress.
*/
/* Mesa's dispatch table is different across library versions, have to modify mesa's table using offset info functions*/
/* Handle glx api.
* In the end application call would look like this:
* app call glxFoo->(mesa asm dispatch stub patched with vbox_glXFoo:jmp glxim[Foo's index])->VBOXGLXTAG(glxFoo)
*/
/* Fill structure used by our assembly stubs */
/* Now patch functions exported by libGL.so */
}
/*
* @todo we're missing first glx related call from the client application.
* Luckily, this doesn't add much problems, except for some cases.
*/
/* __DRIcoreExtension */
static __DRIscreen *
void *loaderPrivate)
{
(void) fd;
(void) sarea_handle;
}
static void
{
}
static const __DRIextension **
{
}
static int
unsigned int attrib,
unsigned int *value)
{
}
static int
{
}
static __DRIdrawable *
const __DRIconfig *config,
unsigned int drawable_id,
unsigned int head,
void *loaderPrivate)
{
(void) drawable_id;
(void) head;
}
static void
{
}
static void
{
}
static __DRIcontext *
const __DRIconfig *config,
void *loaderPrivate)
{
}
static int
unsigned long mask)
{
}
static void
{
}
static int
{
}
static int
{
}
/* __DRIlegacyExtension */
static __DRIscreen *
const __DRIversion *ddx_version,
const __DRIversion *dri_version,
const __DRIversion *drm_version,
const __DRIframebuffer *frame_buffer,
const __DRIextension **extensions,
const __DRIconfig ***driver_modes,
void *loaderPrivate)
{
(void) ddx_version;
(void) dri_version;
(void) frame_buffer;
(void) pSAREA;
(void) fd;
}
static __DRIdrawable *
{
(void) hwDrawable;
(void) renderType;
(void) attrs;
(void) data;
}
static __DRIcontext *
{
(void) render_type;
(void) hwContext;
}
static const __DRIlegacyExtension vboxdriLegacyExtension = {
};
static const __DRIcoreExtension vboxdriCoreExtension = {
{ __DRI_CORE, __DRI_CORE_VERSION },
vboxdriCreateNewScreen, /* driCreateNewScreen */
vboxdriCreateNewDrawable, /* driCreateNewDrawable */
};
/* This structure is used by dri_util from mesa, don't rename it! */
};