VirtualBox

Changeset 34177 in vbox for trunk/src/VBox/Additions


Ignore:
Timestamp:
Nov 18, 2010 3:12:24 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
67904
Message:

crOpenGL: fix for 64bit linuxes

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/crOpenGL/fakedri_drv.c

    r33540 r34177  
    8282#else
    8383# define DRI_ELFSYM Elf32_Sym
     84#endif
     85
     86#ifdef RT_ARCH_AMD64
     87typedef struct _FAKEDRI_PatchNode
     88{
     89    const char* psFuncName;
     90    void *pDstStart, *pDstEnd;
     91    const void *pSrcStart, *pSrcEnd;
     92
     93    struct _FAKEDRI_PatchNode *pNext;
     94} FAKEDRI_PatchNode;
     95static FAKEDRI_PatchNode *g_pFreeList=NULL, *g_pRepatchList=NULL;
    8496#endif
    8597
     
    129141
    130142static void
     143vboxApplyPatch(const char* psFuncName, void *pDst, const void *pSrc, unsigned long size)
     144{
     145    void *alPatch;
     146    int rv;
     147
     148    /* Get aligned start address we're going to patch*/
     149    alPatch = (void*) ((uintptr_t)pDst & ~(uintptr_t)(PAGESIZE-1));
     150
     151#ifndef VBOX_NO_MESA_PATCH_REPORTS
     152    crDebug("MProtecting: %p, %li", alPatch, pDst-alPatch+size);
     153#endif
     154
     155    /* Get write access to mesa functions */
     156    rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_WRITE|RTMEM_PROT_EXEC);
     157    if (RT_FAILURE(rv))
     158    {
     159        crError("mprotect failed with %x (%s)", rv, psFuncName);
     160    }
     161
     162#ifndef VBOX_NO_MESA_PATCH_REPORTS
     163    crDebug("Writing %li bytes to %p from %p", size, pDst, pSrc);
     164#endif
     165
     166    crMemcpy(pDst, pSrc, size);
     167
     168    /*@todo Restore the protection, probably have to check what was it before us...*/
     169    rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_EXEC);
     170    if (RT_FAILURE(rv))
     171    {
     172        crError("mprotect2 failed with %x (%s)", rv, psFuncName);
     173    }
     174}
     175
     176static void
    131177vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd)
    132178{
     
    172218
    173219        pEnd = pStart + sym1->st_size;
     220# ifndef VBOX_NO_MESA_PATCH_REPORTS
     221        crDebug("VBox Entry: %p, start: %p(%s:%s), size: %li", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
     222# endif
     223    }
     224#endif
     225
    174226#ifndef VBOX_NO_MESA_PATCH_REPORTS
    175         crDebug("VBox Entry: %p, start: %p(%s:%s), size: %i", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
    176 #endif
    177     }
    178 #endif
    179 
    180 #ifndef VBOX_NO_MESA_PATCH_REPORTS
    181     crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %i", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
    182     crDebug("Vbox code: start: %p, end %p, size: %i", pStart, pEnd, pEnd-pStart);
     227    crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %li", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
     228    crDebug("Vbox code: start: %p, end %p, size: %li", pStart, pEnd, pEnd-pStart);
    183229#endif
    184230
     
    189235        /* Try to insert 5 bytes jmp/jmpq to our stub code */
    190236
    191         if (5>(pEnd-pStart))
    192         {
    193             crDebug("Can't patch size too small.(%s)", psFuncName);
     237        if (sym->st_size<5)
     238        {
     239            if (crStrcmp(psFuncName, "glXCreateGLXPixmapMESA"))
     240            {
     241                crError("Can't patch size too small.(%s)", psFuncName);
     242            }
    194243            return;
    195244        }
    196245
    197246        shift = (void*)((intptr_t)pStart-((intptr_t)dlip.dli_saddr+5));
    198 # ifndef VBOX_NO_MESA_PATCH_REPORTS
     247#ifndef VBOX_NO_MESA_PATCH_REPORTS
    199248        crDebug("Inserting jmp[q] with shift %p instead", shift);
    200 # endif
     249#endif
    201250
    202251#ifdef RT_ARCH_AMD64
     
    206255            if (offset>INT32_MAX || offset<INT32_MIN)
    207256            {
    208                 crDebug("Can't patch offset is too big.(%s)", psFuncName);
     257                FAKEDRI_PatchNode *pNode;
     258# ifndef VBOX_NO_MESA_PATCH_REPORTS
     259                crDebug("Can't patch offset is too big. Pushing for 2nd pass(%s)", psFuncName);
     260# endif
     261                /*Add patch node to repatch with chain jmps in 2nd pass*/
     262                pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
     263                if (!pNode)
     264                {
     265                    crError("Not enough memory.");
     266                    return;
     267                }
     268                pNode->psFuncName = psFuncName;
     269                pNode->pDstStart = dlip.dli_saddr;
     270                pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
     271                pNode->pSrcStart = pStart;
     272                pNode->pSrcEnd = pEnd;
     273                pNode->pNext = g_pRepatchList;
     274                g_pRepatchList = pNode;
    209275                return;
    210276            }
     
    213279
    214280        patch[0] = 0xE9;
    215         patch[1] = ((char*)&shift)[0];
    216         patch[2] = ((char*)&shift)[1];
    217         patch[3] = ((char*)&shift)[2];
    218         patch[4] = ((char*)&shift)[3];
    219 
    220 # ifndef VBOX_NO_MESA_PATCH_REPORTS
     281        crMemcpy(&patch[1], &shift, 4);
     282#ifndef VBOX_NO_MESA_PATCH_REPORTS
    221283        crDebug("Patch: E9 %x", *((int*)&patch[1]));
    222 # endif
     284#endif
    223285        pStart = &patch[0];
    224286        pEnd = &patch[5];
    225287    }
    226288
    227     /* Get aligned start address we're going to patch*/
    228     alPatch = (void*) ((uintptr_t)dlip.dli_saddr & ~(uintptr_t)(PAGESIZE-1));
    229 
    230 #ifndef VBOX_NO_MESA_PATCH_REPORTS
    231     crDebug("MProtecting: %p, %i", alPatch, dlip.dli_saddr-alPatch+pEnd-pStart);
    232 #endif
    233 
    234     /* Get write access to mesa functions */
    235     rv = RTMemProtect(alPatch, dlip.dli_saddr-alPatch+pEnd-pStart,
    236                       RTMEM_PROT_READ|RTMEM_PROT_WRITE|RTMEM_PROT_EXEC);
    237     if (RT_FAILURE(rv))
    238     {
    239         crError("mprotect failed with %x (%s)", rv, psFuncName);
    240     }
    241 
    242 #ifndef VBOX_NO_MESA_PATCH_REPORTS
    243     crDebug("Writing %i bytes to %p from %p", pEnd-pStart, dlip.dli_saddr, pStart);
    244 #endif
    245 
    246     crMemcpy(dlip.dli_saddr, pStart, pEnd-pStart);
    247 
    248     /*@todo Restore the protection, probably have to check what was it before us...*/
    249     rv = RTMemProtect(alPatch, dlip.dli_saddr-alPatch+pEnd-pStart,
    250                       RTMEM_PROT_READ|RTMEM_PROT_EXEC);
    251     if (RT_FAILURE(rv))
    252     {
    253         crError("mprotect2 failed with %x (%s)", rv, psFuncName);
    254     }
    255 }
     289    vboxApplyPatch(psFuncName, dlip.dli_saddr, pStart, pEnd-pStart);
     290
     291#ifdef RT_ARCH_AMD64
     292    /*Add rest of mesa function body to free list*/
     293    if (sym->st_size-(pEnd-pStart)>=5)
     294    {
     295        FAKEDRI_PatchNode *pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
     296        if (pNode)
     297        {
     298                pNode->psFuncName = psFuncName;
     299                pNode->pDstStart = dlip.dli_saddr+(pEnd-pStart);
     300                pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
     301                pNode->pSrcStart = dlip.dli_saddr;
     302                pNode->pSrcEnd = NULL;
     303                pNode->pNext = g_pFreeList;
     304                g_pFreeList = pNode;
     305        }
     306    }
     307#endif
     308}
     309
     310#ifdef RT_ARCH_AMD64
     311static void
     312vboxRepatchMesaExports(void)
     313{
     314    FAKEDRI_PatchNode *pFreeNode, *pPatchNode;
     315    int64_t offset;
     316    char patch[12];
     317
     318    pPatchNode = g_pRepatchList;
     319    while (pPatchNode)
     320    {
     321# ifndef VBOX_NO_MESA_PATCH_REPORTS
     322        crDebug("\nvboxRepatchMesaExports %s", pPatchNode->psFuncName);
     323# endif
     324        /*find free place in mesa functions, to place 64bit jump to our stub code*/
     325        pFreeNode = g_pFreeList;
     326        while (pFreeNode)
     327        {
     328            if (pFreeNode->pDstEnd-pFreeNode->pDstStart>=12)
     329            {
     330                offset = ((intptr_t)pFreeNode->pDstStart-((intptr_t)pPatchNode->pDstStart+5));
     331                if (offset<=INT32_MAX && offset>=INT32_MIN)
     332                {
     333                    break;
     334                }
     335            }
     336            pFreeNode=pFreeNode->pNext;
     337        }
     338
     339        if (!pFreeNode)
     340        {
     341            crError("Failed to find free space, to place repatch for %s.", pPatchNode->psFuncName);
     342            return;
     343        }
     344
     345        /*add 32bit rel jmp, from mesa orginal function to free space in other mesa function*/
     346        patch[0] = 0xE9;
     347        crMemcpy(&patch[1], &offset, 4);
     348# ifndef VBOX_NO_MESA_PATCH_REPORTS
     349        crDebug("Adding jmp from mesa %s to mesa %s+%#lx", pPatchNode->psFuncName, pFreeNode->psFuncName,
     350                pFreeNode->pDstStart-pFreeNode->pSrcStart);
     351# endif
     352        vboxApplyPatch(pPatchNode->psFuncName, pPatchNode->pDstStart, &patch[0], 5);
     353
     354        /*add 64bit abs jmp, from free space to our stub code*/
     355        patch[0] = 0x48; /*movq %rax,imm64*/
     356        patch[1] = 0xB8;
     357        crMemcpy(&patch[2], &pPatchNode->pSrcStart, 8);
     358        patch[10] = 0xFF; /*jmp *%rax*/
     359        patch[11] = 0xE0;
     360# ifndef VBOX_NO_MESA_PATCH_REPORTS
     361        crDebug("Adding jmp from mesa %s+%#lx to vbox %s", pFreeNode->psFuncName, pFreeNode->pDstStart-pFreeNode->pSrcStart,
     362                pPatchNode->psFuncName);
     363# endif
     364        vboxApplyPatch(pFreeNode->psFuncName, pFreeNode->pDstStart, &patch[0], 12);
     365        /*mark this space as used*/
     366        pFreeNode->pDstStart = pFreeNode->pDstStart+12;
     367
     368        pPatchNode = pPatchNode->pNext;
     369    }
     370}
     371
     372static void
     373vboxFakeDriFreeList(FAKEDRI_PatchNode *pList)
     374{
     375    FAKEDRI_PatchNode *pNode;
     376
     377    while (pList)
     378    {
     379        pNode=pList;
     380        pList=pNode->pNext;
     381        crFree(pNode);
     382    }
     383}
     384#endif
    256385
    257386#ifdef VBOX_OGL_GLX_USE_CSTUBS
     
    267396    crDebug("Patching mesa glx entries");
    268397    #include "fakedri_glxfuncsList.h"
     398
     399#ifdef RT_ARCH_AMD64
     400    vboxRepatchMesaExports();
     401    vboxFakeDriFreeList(g_pRepatchList);
     402    g_pRepatchList = NULL;
     403    vboxFakeDriFreeList(g_pFreeList);
     404    g_pFreeList = NULL;
     405#endif
    269406}
    270407#undef GLXAPI_ENTRY
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette