aboutsummaryrefslogtreecommitdiffstats
path: root/tools/ioemu/iodev/plugin.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/ioemu/iodev/plugin.cc')
-rw-r--r--tools/ioemu/iodev/plugin.cc554
1 files changed, 554 insertions, 0 deletions
diff --git a/tools/ioemu/iodev/plugin.cc b/tools/ioemu/iodev/plugin.cc
new file mode 100644
index 0000000000..136065d9d8
--- /dev/null
+++ b/tools/ioemu/iodev/plugin.cc
@@ -0,0 +1,554 @@
+/////////////////////////////////////////////////////////////////////////
+// $Id: plugin.cc,v 1.8 2003/07/31 12:04:47 vruppert 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, Bit8u mask) = 0;
+int (*pluginRegisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+ unsigned base, const char *name, Bit8u mask) = 0;
+int (*pluginRegisterDefaultIOReadHandler)(void *thisPtr, ioReadHandler_t callback,
+ const char *name, Bit8u mask) = 0;
+int (*pluginRegisterDefaultIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback,
+ const char *name, Bit8u mask) = 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 */
+#if BX_PLUGINS
+static void plugin_init_one(plugin_t *plugin);
+#endif
+
+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, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_io_read_handler (thisPtr, callback, base, name, mask);
+ 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, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_io_write_handler (thisPtr, callback, base, name, mask);
+ 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, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_default_io_read_handler (thisPtr, callback, name, mask);
+ pluginlog->ldebug("plugin %s registered default I/O read ", name);
+ return 0;
+}
+
+ static int
+builtinRegisterDefaultIOWriteHandler(void *thisPtr, ioWriteHandler_t callback,
+ const char *name, Bit8u mask)
+{
+ BX_ASSERT (mask<8);
+ bx_devices.register_default_io_write_handler (thisPtr, callback, name, mask);
+ 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
+ pluginlog = new logfunctions();
+ pluginlog->put("PLGIN");
+ pluginlog->settype(PLUGINLOG);
+ 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 */
+/************************************************************************/
+
+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;
+}
+#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);
+ }
+ }
+}