Bochs/bochs/plugin.cc
Bryce Denney cec9135e9f - Apply patch.replace-Boolean rev 1.3. Every "Boolean" is now changed to a
"bx_bool" which is always defined as Bit32u on all platforms.  In Carbon
  specific code, Boolean is still used because the Carbon header files
  define it to unsigned char.
- this fixes bug [ 623152 ] MacOSX: Triple Exception Booting win95.
  The bug was that some code in Bochs depends on Boolean to be a
  32 bit value.  (This should be fixed, but I don't know all the places
  where it needs to be fixed yet.)  Because Carbon defined Boolean as
  an unsigned char, Bochs just followed along and used the unsigned char
  definition to avoid compile problems.  This exposed the dependency
  on 32 bit Boolean on MacOS X only and led to major simulation problems,
  that could only be reproduced and debugged on that platform.
- On the mailing list we debated whether to make all Booleans into "bool" or
  our own type.  I chose bx_bool for several reasons.
  1. Unlike C++'s bool, we can guarantee that bx_bool is the same size on all
     platforms, which makes it much less likely to have more platform-specific
     simulation differences in the future.  (I spent hours on a borrowed
     MacOSX machine chasing bug 618388 before discovering that different sized
     Booleans were the problem, and I don't want to repeat that.)
  2. We still have at least one dependency on 32 bit Booleans which must be
     fixed some time, but I don't want to risk introducing new bugs into the
     simulation just before the 2.0 release.

Modified Files:
    bochs.h config.h.in gdbstub.cc logio.cc main.cc pc_system.cc
    pc_system.h plugin.cc plugin.h bios/rombios.c cpu/apic.cc
    cpu/arith16.cc cpu/arith32.cc cpu/arith64.cc cpu/arith8.cc
    cpu/cpu.cc cpu/cpu.h cpu/ctrl_xfer16.cc cpu/ctrl_xfer32.cc
    cpu/ctrl_xfer64.cc cpu/data_xfer16.cc cpu/data_xfer32.cc
    cpu/data_xfer64.cc cpu/debugstuff.cc cpu/exception.cc
    cpu/fetchdecode.cc cpu/flag_ctrl_pro.cc cpu/init.cc
    cpu/io_pro.cc cpu/lazy_flags.cc cpu/lazy_flags.h cpu/mult16.cc
    cpu/mult32.cc cpu/mult64.cc cpu/mult8.cc cpu/paging.cc
    cpu/proc_ctrl.cc cpu/segment_ctrl_pro.cc cpu/stack_pro.cc
    cpu/tasking.cc debug/dbg_main.cc debug/debug.h debug/sim2.cc
    disasm/dis_decode.cc disasm/disasm.h doc/docbook/Makefile
    docs-html/cosimulation.html fpu/wmFPUemu_glue.cc
    gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/gui.cc gui/gui.h
    gui/keymap.cc gui/keymap.h gui/macintosh.cc gui/nogui.cc
    gui/rfb.cc gui/sdl.cc gui/siminterface.cc gui/siminterface.h
    gui/term.cc gui/win32.cc gui/wx.cc gui/wxmain.cc gui/wxmain.h
    gui/x.cc instrument/example0/instrument.cc
    instrument/example0/instrument.h
    instrument/example1/instrument.cc
    instrument/example1/instrument.h
    instrument/stubs/instrument.cc instrument/stubs/instrument.h
    iodev/cdrom.cc iodev/cdrom.h iodev/cdrom_osx.cc iodev/cmos.cc
    iodev/devices.cc iodev/dma.cc iodev/dma.h iodev/eth_arpback.cc
    iodev/eth_packetmaker.cc iodev/eth_packetmaker.h
    iodev/floppy.cc iodev/floppy.h iodev/guest2host.h
    iodev/harddrv.cc iodev/harddrv.h iodev/ioapic.cc
    iodev/ioapic.h iodev/iodebug.cc iodev/iodev.h
    iodev/keyboard.cc iodev/keyboard.h iodev/ne2k.h
    iodev/parallel.h iodev/pci.cc iodev/pci.h iodev/pic.h
    iodev/pit.cc iodev/pit.h iodev/pit_wrap.cc iodev/pit_wrap.h
    iodev/sb16.cc iodev/sb16.h iodev/serial.cc iodev/serial.h
    iodev/vga.cc iodev/vga.h memory/memory.h memory/misc_mem.cc
2002-10-25 11:44:41 +00:00

625 lines
18 KiB
C++

/////////////////////////////////////////////////////////////////////////
// $Id: plugin.cc,v 1.3 2002-10-25 11:44:33 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 "lib%s.la"
#else
#define PLUGIN_FILENAME_FORMAT "%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 */
/************************************************************************/
#warning BBD: when all plugin devices are converted to the "bx_devmodel" type with virtual functions, I intend to chop this out.
// (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);
}
}
}