Bochs/bochs/plugin.cc
Bryce Denney 1bd9a44a9e - plugins are now called libbx_NAME.so for unix and bx_NAME.dll for win32.
- plugins are installed into ${plugdir} which is defined to be
  ${libdir}/bochs-${VERSION}/plugins.

Modified Files:
  Makefile.in plugin.cc configure.in configure gui/Makefile.in
  iodev/Makefile.in
2002-11-14 18:45:49 +00:00

627 lines
18 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id: plugin.cc,v 1.5 2002-11-14 18:45:41 bdenney Exp $
/////////////////////////////////////////////////////////////////////////
//
// This file defines the plugin and plugin-device registration functions and
// the device registration functions. It handles dynamic loading of modules,
// using the LTDL library for cross-platform support.
//
// This file is based on the plugin.c file from plex86, but with significant
// changes to make it work in Bochs.
// Plex86 is Copyright (C) 1999-2000 The plex86 developers team
//
/////////////////////////////////////////////////////////////////////////
#include "bochs.h"
#include "plugin.h"
#define LOG_THIS genlog->
#define PLUGIN_INIT_FMT_STRING "lib%s_LTX_plugin_init"
#define PLUGIN_FINI_FMT_STRING "lib%s_LTX_plugin_fini"
#define PLUGIN_PATH ""
#ifndef WIN32
#define PLUGIN_FILENAME_FORMAT "libbx_%s.la"
#else
#define PLUGIN_FILENAME_FORMAT "bx_%s.dll"
#endif
void (*pluginRegisterIRQ)(unsigned irq, const char* name) = 0;
void (*pluginUnregisterIRQ)(unsigned irq, const char* name) = 0;
void (* pluginResetSignal)(unsigned sig) = 0;
void (*pluginSetHRQ)(unsigned val) = 0;
void (*pluginSetHRQHackCallback)( void (*callback)(void) ) = 0;
int (*pluginRegisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
unsigned base, const char *name, unsigned len) = 0;
int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
unsigned base, const char *name, unsigned len) = 0;
int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
const char *name, unsigned len) = 0;
int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
const char *name, unsigned len) = 0;
int (*pluginRegisterTimer)(void *this_ptr, void (*funct)(void *),
Bit32u useconds, bx_bool continuous,
bx_bool active, const char* name) = 0;
void (*pluginActivateTimer)(unsigned id, Bit32u usec, bx_bool continuous) = 0;
void (*pluginHRQHackCallback)(void);
unsigned pluginHRQ = 0;
plugin_t *plugins = NULL; /* Head of the linked list of plugins */
static void plugin_init_one(plugin_t *plugin);
device_t *devices = NULL; /* Head of the linked list of registered devices */
plugin_t *current_plugin_context = NULL;
/************************************************************************/
/* Builtins declarations */
/************************************************************************/
static void
builtinRegisterIRQ(unsigned irq, const char* name)
{
#if 0
pluginlog->panic("builtinRegisterIRQ called, no pic plugin loaded?");
#else
bx_devices.register_irq(irq, name);
#endif
}
static void
builtinUnregisterIRQ(unsigned irq, const char* name)
{
#if 0
pluginlog->panic("builtinUnregisterIRQ called, no pic plugin loaded?");
#else
bx_devices.unregister_irq(irq, name);
#endif
}
static void
builtinSetHRQ(unsigned val)
{
#if 0
pluginlog->panic("builtinSetHRQ called, no plugin loaded?");
#else
pluginHRQ = val;
#endif
}
static void
builtinSetHRQHackCallback( void (*callback)(void) )
{
#if 0
pluginlog->panic("builtinSetHRQHackCallback called, no plugin loaded?");
#else
pluginHRQHackCallback = callback;
#endif
}
static void
builtinResetSignal( unsigned )
{
pluginlog->panic("builtinResetSignal called, no plugin loaded?");
}
static int
builtinRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback,
unsigned base, const char *name, unsigned len)
{
BX_ASSERT (len<8);
bx_devices.register_io_read_handler (thisPtr, callback, base, name);
pluginlog->ldebug("plugin %s registered I/O read address at %04x", name, base);
return 0;
}
static int
builtinRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
unsigned base, const char *name, unsigned len)
{
BX_ASSERT (len<8);
bx_devices.register_io_write_handler (thisPtr, callback, base, name);
pluginlog->ldebug("plugin %s registered I/O write address at %04x", name, base);
return 0;
}
static int
builtinRegisterDefaultIOReadHandler(void *thisPtr, ioReadHandler_t callback,
const char *name, unsigned len)
{
BX_ASSERT (len<8);
bx_devices.register_default_io_read_handler (thisPtr, callback, name);
pluginlog->ldebug("plugin %s registered default I/O read ", name);
return 0;
}
static int
builtinRegisterDefaultIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
const char *name, unsigned len)
{
BX_ASSERT (len<8);
bx_devices.register_default_io_write_handler (thisPtr, callback, name);
pluginlog->ldebug("plugin %s registered default I/O write ", name);
return 0;
}
static int
builtinRegisterTimer(void *this_ptr, void (*funct)(void *),
Bit32u useconds, bx_bool continuous,
bx_bool active, const char* name)
{
int id = bx_pc_system.register_timer (this_ptr, funct, useconds, continuous, active, name);
pluginlog->ldebug("plugin %s registered timer %d", name, id);
return id;
}
static void
builtinActivateTimer(unsigned id, Bit32u usec, bx_bool continuous)
{
bx_pc_system.activate_timer (id, usec, continuous);
pluginlog->ldebug("plugin activated timer %d", id);
}
#if BX_PLUGINS
/************************************************************************/
/* Plugin initialization / deinitialization */
/************************************************************************/
void
plugin_init_all (void)
{
plugin_t *plugin;
pluginlog->info("Initializing plugins");
for (plugin = plugins; plugin; plugin = plugin->next)
{
char *arg_ptr = plugin->args;
/* process the command line */
plugin->argc = 0;
while (plugin->argc < MAX_ARGC)
{
while (*arg_ptr && isspace (*arg_ptr))
arg_ptr++;
if (!*arg_ptr)
break;
plugin->argv[plugin->argc++] = arg_ptr;
while (*arg_ptr && !isspace (*arg_ptr))
arg_ptr++;
if (!*arg_ptr)
break;
*arg_ptr++ = '\0';
}
/* initialize the plugin */
if (plugin->plugin_init (plugin, plugin->type, plugin->argc, plugin->argv))
{
pluginlog->panic("Plugin initialization failed for %s", plugin->name);
plugin_abort();
}
plugin->initialized = 1;
}
return;
}
void
plugin_init_one(plugin_t *plugin)
{
char *arg_ptr = plugin->args;
/* process the command line */
plugin->argc = 0;
while (plugin->argc < MAX_ARGC)
{
while (*arg_ptr && isspace (*arg_ptr))
arg_ptr++;
if (!*arg_ptr)
break;
plugin->argv[plugin->argc++] = arg_ptr;
while (*arg_ptr && !isspace (*arg_ptr))
arg_ptr++;
if (!*arg_ptr)
break;
*arg_ptr++ = '\0';
}
/* initialize the plugin */
if (plugin->plugin_init (plugin, plugin->type, plugin->argc, plugin->argv))
{
pluginlog->info("Plugin initialization failed for %s", plugin->name);
plugin_abort();
}
plugin->initialized = 1;
}
plugin_t *
plugin_unload(plugin_t *plugin)
{
plugin_t *dead_plug;
if (plugin->initialized)
plugin->plugin_fini ();
lt_dlclose (plugin->handle);
free (plugin->name);
free (plugin->args);
dead_plug = plugin;
plugin = plugin->next;
free (dead_plug);
return plugin;
}
void
plugin_fini_all (void)
{
plugin_t *plugin;
for (plugin = plugins; plugin; plugin = plugin_unload (plugin));
return;
}
void
plugin_load (char *name, char *args, plugintype_t type)
{
plugin_t *plugin;
plugin = (plugin_t *)malloc (sizeof (plugin_t));
if (!plugin)
{
BX_PANIC (("malloc plugin_t failed"));
}
plugin->type = type;
plugin->name = name;
plugin->args = args;
plugin->initialized = 0;
char plugin_filename[BX_PATHNAME_LEN], buf[BX_PATHNAME_LEN];
sprintf (buf, PLUGIN_FILENAME_FORMAT, name);
sprintf(plugin_filename, "%s%s", PLUGIN_PATH, buf);
// Set context so that any devices that the plugin registers will
// be able to see which plugin created them. The registration will
// be called from either dlopen (global constructors) or plugin_init.
BX_ASSERT (current_plugin_context == NULL);
current_plugin_context = plugin;
plugin->handle = lt_dlopen (plugin_filename);
BX_INFO (("lt_dlhandle is %p", plugin->handle));
if (!plugin->handle)
{
current_plugin_context = NULL;
BX_PANIC (("dlopen failed for module '%s': %s", name, lt_dlerror ()));
free (plugin);
return;
}
sprintf (buf, PLUGIN_INIT_FMT_STRING, name);
plugin->plugin_init =
(int (*)(struct _plugin_t *, enum plugintype_t, int, char *[])) /* monster typecast */
lt_dlsym (plugin->handle, buf);
if (plugin->plugin_init == NULL) {
pluginlog->panic("could not find plugin_init: %s", lt_dlerror ());
plugin_abort ();
}
sprintf (buf, PLUGIN_FINI_FMT_STRING, name);
plugin->plugin_fini = (void (*)(void)) lt_dlsym (plugin->handle, buf);
if (plugin->plugin_init == NULL) {
pluginlog->panic("could not find plugin_fini: %s", lt_dlerror ());
plugin_abort ();
}
pluginlog->info("loaded plugin %s",plugin_filename);
/* Insert plugin at the _end_ of the plugin linked list. */
plugin->next = NULL;
if (!plugins)
{
/* Empty list, this become the first entry. */
plugins = plugin;
}
else
{
/* Non-empty list. Add to end. */
plugin_t *temp = plugins;
while (temp->next)
temp = temp->next;
temp->next = plugin;
}
plugin_init_one(plugin);
// check that context didn't change. This should only happen if we
// need a reentrant plugin_load.
BX_ASSERT (current_plugin_context == plugin);
current_plugin_context = NULL;
return;
}
void
plugin_abort (void)
{
pluginlog->panic("plugin load aborted");
}
#endif /* end of #if BX_PLUGINS */
/************************************************************************/
/* Plugin system: initialisation of plugins entry points */
/************************************************************************/
void
plugin_startup(void)
{
pluginRegisterIRQ = builtinRegisterIRQ;
pluginUnregisterIRQ = builtinUnregisterIRQ;
pluginResetSignal = builtinResetSignal;
pluginSetHRQHackCallback = builtinSetHRQHackCallback;
pluginSetHRQ = builtinSetHRQ;
pluginRegisterIOReadHandler = builtinRegisterIOReadHandler;
pluginRegisterIOWriteHandler = builtinRegisterIOWriteHandler;
pluginRegisterDefaultIOReadHandler = builtinRegisterDefaultIOReadHandler;
pluginRegisterDefaultIOWriteHandler = builtinRegisterDefaultIOWriteHandler;
pluginRegisterTimer = builtinRegisterTimer;
pluginActivateTimer = builtinActivateTimer;
#if BX_PLUGINS
int status = lt_dlinit ();
if (status != 0) {
BX_ERROR (("initialization error in ltdl library (for loading plugins)"));
BX_PANIC (("error message was: %s", lt_dlerror ()));
}
#endif
}
/************************************************************************/
/* Plugin system: Device registration */
/************************************************************************/
#ifdef __GNUC__
#warning BBD: when all plugin devices are converted to the "bx_devmodel" type with virtual functions, I intend to chop this out.
#endif
// (and the nasty current_plugin_context hack can go too)
void pluginRegisterDevice(deviceInitMem_t init1, deviceInitDev_t init2,
deviceReset_t reset, deviceLoad_t load,
deviceSave_t save, char *name)
{
device_t *device;
device = (device_t *)malloc (sizeof (device_t));
if (!device)
{
pluginlog->panic("can't allocate device_t");
}
device->name = name;
BX_ASSERT(current_plugin_context != NULL);
device->plugin = current_plugin_context;
device->use_devmodel_interface = 0;
device->device_init_mem = init1;
device->device_init_dev = init2;
device->device_reset = reset;
device->device_load_state = load;
device->device_save_state = save;
device->next = NULL;
// Don't add every kind of device to the list.
switch (device->plugin->type)
{
case PLUGTYPE_CORE:
// Core devices are present whether or not we are using plugins, so
// they are managed by code iodev/devices.cc and should not be
// managed by the plugin system.
return; // Do not add core devices to the devices list.
case PLUGTYPE_OPTIONAL:
case PLUGTYPE_USER:
default:
// The plugin system will manage optional and user devices only.
break;
}
if (!devices)
{
/* Empty list, this become the first entry. */
devices = device;
}
else
{
/* Non-empty list. Add to end. */
device_t *temp = devices;
while (temp->next)
temp = temp->next;
temp->next = device;
}
}
void pluginRegisterDeviceDevmodel(plugin_t *plugin, plugintype_t type, bx_devmodel_c *devmodel, char *name)
{
device_t *device;
device = (device_t *)malloc (sizeof (device_t));
if (!device)
{
pluginlog->panic("can't allocate device_t");
}
device->name = name;
BX_ASSERT (devmodel != NULL);
device->devmodel = devmodel;
device->plugin = plugin; // this can be NULL
device->use_devmodel_interface = 1;
device->device_init_mem = NULL; // maybe should use 1 to detect any use?
device->device_init_dev = NULL;
device->device_reset = NULL;
device->device_load_state = NULL;
device->device_save_state = NULL;
device->next = NULL;
// Don't add every kind of device to the list.
switch (type) {
case PLUGTYPE_CORE:
// Core devices are present whether or not we are using plugins, so
// they are managed by the same code in iodev/devices.cc whether
// plugins are on or off.
return; // Do not add core devices to the devices list.
case PLUGTYPE_OPTIONAL:
case PLUGTYPE_USER:
default:
// The plugin system will manage optional and user devices only.
break;
}
if (!devices)
{
/* Empty list, this become the first entry. */
devices = device;
}
else
{
/* Non-empty list. Add to end. */
device_t *temp = devices;
while (temp->next)
temp = temp->next;
temp->next = device;
}
}
/************************************************************************/
/* Plugin system: Check if a plugin is loaded */
/************************************************************************/
bx_bool pluginDevicePresent(char *name)
{
device_t *device;
for (device = devices; device; device = device->next)
{
if (strcmp(device->name,name)==0) return true;
}
return false;
}
#if BX_PLUGINS
/************************************************************************/
/* Plugin system: Load one plugin */
/************************************************************************/
int bx_load_plugin (const char *name, plugintype_t type)
{
char *namecopy = new char[1+strlen(name)];
strcpy (namecopy, name);
plugin_load (namecopy, "", type);
return 0;
}
/************************************************************************/
/* Plugin system: Load ALL plugins */
/************************************************************************/
int bx_load_plugins (void)
{
pluginlog = new logfunctions();
pluginlog->put("PLGIN");
pluginlog->settype(PLUGINLOG);
#if !BX_PLUGINS
pluginlog->info("plugins deactivated");
#endif
return 0;
}
#endif /* end of #if BX_PLUGINS */
/*************************************************************************/
/* Plugin system: Execute init function of all registered plugin-devices */
/*************************************************************************/
void bx_init_plugins()
{
device_t *device;
// two loops
for (device = devices; device; device = device->next)
{
if (!device->use_devmodel_interface) {
if (device->device_init_mem != NULL) {
pluginlog->info("init_mem of '%s' plugin device by function pointer",device->name);
device->device_init_mem(BX_MEM(0));
}
} else {
pluginlog->info("init_mem of '%s' plugin device by virtual method",device->name);
device->devmodel->init_mem (BX_MEM(0));
}
}
for (device = devices; device; device = device->next)
{
if (!device->use_devmodel_interface) {
if (device->device_init_dev != NULL) {
pluginlog->info("init_dev of '%s' plugin device by function pointer",device->name);
device->device_init_dev();
}
} else {
pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name);
device->devmodel->init ();
}
}
}
/**************************************************************************/
/* Plugin system: Execute reset function of all registered plugin-devices */
/**************************************************************************/
void bx_reset_plugins(unsigned signal)
{
device_t *device;
for (device = devices; device; device = device->next)
{
if (!device->use_devmodel_interface) {
if (device->device_reset != NULL) {
pluginlog->info("reset of '%s' plugin device by function pointer",device->name);
device->device_reset(signal);
}
} else {
pluginlog->info("reset of '%s' plugin device by virtual method",device->name);
device->devmodel->reset (signal);
}
}
}