spuload.c revision d1ef52979a515c51fdbbe00ce6a5912ef7e968c0
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson/* Copyright (c) 2001, Stanford University
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson * All rights reserved
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson *
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson * See the file LICENSE.txt for information on redistributing this software.
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson */
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include "cr_mem.h"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include "cr_environment.h"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include "cr_string.h"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include "cr_dll.h"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include "cr_error.h"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include "cr_spu.h"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include <iprt/param.h>
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include <iprt/string.h>
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include <iprt/path.h>
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#include <stdio.h>
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#ifdef WINDOWS
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#define DLL_SUFFIX ".dll"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#define DLL_PREFIX "VBoxOGL"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#elif defined(DARWIN)
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#define DLL_SUFFIX ".dylib"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#define DLL_PREFIX "VBoxOGL"
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson/*
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#define DLL_SUFFIX ".bundle"
2f0f7926326cc76419b074fd91a589cb68980ffbdugan#define DLL_PREFIX ""
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson*/
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#else
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#ifdef AIX
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#define DLL_SUFFIX ".o"
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#define DLL_PREFIX "VBoxOGL"
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#else
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#define DLL_SUFFIX ".so"
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#define DLL_PREFIX "VBoxOGL"
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#endif
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#endif
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergaraextern void __buildDispatch( SPU *spu );
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergarastatic char *__findDLL( char *name, char *dir )
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara{
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara static char path[8092];
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara if (!dir)
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara {
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#if defined(DARWIN)
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson char szSharedLibPath[8092];
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara int rc = RTPathAppPrivateArch (szSharedLibPath, sizeof(szSharedLibPath));
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara if (RT_SUCCESS(rc))
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson sprintf ( path, "%s/%s%sspu%s", szSharedLibPath, DLL_PREFIX, name, DLL_SUFFIX );
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson else
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara#endif /* DARWIN */
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson sprintf ( path, "%s%sspu%s", DLL_PREFIX, name, DLL_SUFFIX );
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson }
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara else
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson {
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson sprintf ( path, "%s/%s%sspu%s", dir, DLL_PREFIX, name, DLL_SUFFIX );
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson }
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara return path;
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson}
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson/**
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson * Load a single SPU from disk and initialize it. Is there any reason
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson * to export this from the SPU loader library? */
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergaraSPU * crSPULoad( SPU *child, int id, char *name, char *dir, void *server )
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson{
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson SPU *the_spu;
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson char *path;
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson CRASSERT( name != NULL );
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson the_spu = (SPU*)crAlloc( sizeof( *the_spu ) );
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson the_spu->id = id;
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson the_spu->privatePtr = NULL;
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson path = __findDLL( name, dir );
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara the_spu->dll = crDLLOpen( path, 0/*resolveGlobal*/ );
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson the_spu->entry_point =
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson (SPULoadFunction) crDLLGetNoError( the_spu->dll, SPU_ENTRY_POINT_NAME );
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara if (!the_spu->entry_point)
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara {
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara crError( "Couldn't load the SPU entry point \"%s\" from SPU \"%s\"!",
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara SPU_ENTRY_POINT_NAME, name );
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara crSPUUnloadChain(the_spu);
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara return NULL;
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara }
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara
b26e36d8a08a1c775531659c04abc3d4ed504139jvergara /* This basicall calls the SPU's SPULoad() function */
37f9a536593b696e5a3dcec443e1475f22fb5afdjvergara if (!the_spu->entry_point( &(the_spu->name), &(the_spu->super_name),
da7ab15aee42edf1c4ff33f66ca717f019b4a578lutoff &(the_spu->init), &(the_spu->self),
da7ab15aee42edf1c4ff33f66ca717f019b4a578lutoff &(the_spu->cleanup),
da7ab15aee42edf1c4ff33f66ca717f019b4a578lutoff &(the_spu->options),
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson &(the_spu->spu_flags)) )
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson {
da7ab15aee42edf1c4ff33f66ca717f019b4a578lutoff crError( "I found the SPU \"%s\", but loading it failed!", name );
da7ab15aee42edf1c4ff33f66ca717f019b4a578lutoff crSPUUnloadChain(the_spu);
da7ab15aee42edf1c4ff33f66ca717f019b4a578lutoff return NULL;
da7ab15aee42edf1c4ff33f66ca717f019b4a578lutoff }
1fb669628faa2eb90d370eb249980b3a1807babaneil_a_wilson#ifdef IN_GUEST
if (crStrcmp(the_spu->name,"error"))
{
/* the default super/base class for an SPU is the error SPU */
if (the_spu->super_name == NULL)
{
the_spu->super_name = "error";
}
the_spu->superSPU = crSPULoad( child, id, the_spu->super_name, dir, server );
}
#else
if (crStrcmp(the_spu->name,"hosterror"))
{
/* the default super/base class for an SPU is the error SPU */
if (the_spu->super_name == NULL)
{
the_spu->super_name = "hosterror";
}
the_spu->superSPU = crSPULoad( child, id, the_spu->super_name, dir, server );
}
#endif
else
{
the_spu->superSPU = NULL;
}
crDebug("Initializing %s SPU", name);
the_spu->function_table = the_spu->init( id, child, the_spu, 0, 1 );
if (!the_spu->function_table) {
crDebug("Failed to init %s SPU", name);
crSPUUnloadChain(the_spu);
return NULL;
}
__buildDispatch( the_spu );
/*crDebug( "initializing dispatch table %p (for SPU %s)", (void*)&(the_spu->dispatch_table), name );*/
crSPUInitDispatchTable( &(the_spu->dispatch_table) );
/*crDebug( "Done initializing the dispatch table for SPU %s, calling the self function", name );*/
the_spu->dispatch_table.server = server;
the_spu->self( &(the_spu->dispatch_table) );
/*crDebug( "Done with the self function" );*/
return the_spu;
}
/**
* Load the entire chain of SPUs and initialize all of them.
* This function returns the first one in the chain.
*/
SPU *
crSPULoadChain( int count, int *ids, char **names, char *dir, void *server )
{
int i;
SPU *child_spu = NULL;
CRASSERT( count > 0 );
for (i = count-1 ; i >= 0 ; i--)
{
int spu_id = ids[i];
char *spu_name = names[i];
SPU *the_spu, *temp;
/* This call passes the previous version of spu, which is the SPU's
* "child" in this chain. */
the_spu = crSPULoad( child_spu, spu_id, spu_name, dir, server );
if (!the_spu) {
return NULL;
}
if (child_spu != NULL)
{
/* keep track of this so that people can pass functions through but
* still get updated when API's change on the fly. */
for (temp = the_spu ; temp ; temp = temp->superSPU )
{
struct _copy_list_node *node = (struct _copy_list_node *) crAlloc( sizeof( *node ) );
node->copy = &(temp->dispatch_table);
node->next = child_spu->dispatch_table.copyList;
child_spu->dispatch_table.copyList = node;
}
}
child_spu = the_spu;
}
return child_spu;
}
#if 00
/* XXXX experimental code - not used at this time */
/**
* Like crSPUChangeInterface(), but don't loop over all functions in
* the table to search for 'old_func'.
*/
void
crSPUChangeFunction(SPUDispatchTable *table, unsigned int funcOffset,
void *newFunc)
{
SPUGenericFunction *f = (SPUGenericFunction *) table + funcOffset;
struct _copy_list_node *temp;
CRASSERT(funcOffset < sizeof(*table) / sizeof(SPUGenericFunction));
printf("%s\n", __FUNCTION__);
if (table->mark == 1)
return;
table->mark = 1;
*f = newFunc;
/* update all copies of this table */
#if 1
for (temp = table->copyList ; temp ; temp = temp->next)
{
crSPUChangeFunction( temp->copy, funcOffset, newFunc );
}
#endif
if (table->copy_of != NULL)
{
crSPUChangeFunction( table->copy_of, funcOffset, newFunc );
}
#if 0
for (temp = table->copyList ; temp ; temp = temp->next)
{
crSPUChangeFunction( temp->copy, funcOffset, newFunc );
}
#endif
table->mark = 0;
}
#endif
/**
* Call the cleanup() function for each SPU in a chain, close the SPU
* DLLs and free the SPU objects.
* \param headSPU pointer to the first SPU in the chain
*/
void
crSPUUnloadChain(SPU *headSPU)
{
SPU *the_spu = headSPU, *next_spu;
while (the_spu)
{
crDebug("Cleaning up SPU %s", the_spu->name);
if (the_spu->cleanup)
the_spu->cleanup();
next_spu = the_spu->superSPU;
crDLLClose(the_spu->dll);
crFree(the_spu);
the_spu = next_spu;
}
}