///////////////////////////////////////////////////////////////////////// // $Id$ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2002-2021 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // ///////////////////////////////////////////////////////////////////////// // // 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 "iodev/iodev.h" #include "plugin.h" #ifndef WIN32 #include /* opendir, readdir */ #include /* setlocale */ #endif #define LOG_THIS genlog-> #define PLUGIN_ENTRY_FMT_STRING "lib%s_plugin_entry" #define GUI_PLUGIN_ENTRY_FMT_STRING "lib%s_gui_plugin_entry" #define IMG_PLUGIN_ENTRY_FMT_STRING "lib%s_img_plugin_entry" #define NET_PLUGIN_ENTRY_FMT_STRING "libeth_%s_plugin_entry" #define SND_PLUGIN_ENTRY_FMT_STRING "libsound%s_plugin_entry" #define PLUGIN_PATH "" #ifndef WIN32 #define PLUGIN_FILENAME_FORMAT "libbx_%s.so" #define GUI_PLUGIN_FILENAME_FORMAT "libbx_%s_gui.so" #define IMG_PLUGIN_FILENAME_FORMAT "libbx_%s_img.so" #define NET_PLUGIN_FILENAME_FORMAT "libbx_eth_%s.so" #define SND_PLUGIN_FILENAME_FORMAT "libbx_sound%s.so" #else #define PLUGIN_FILENAME_FORMAT "bx_%s.dll" #define GUI_PLUGIN_FILENAME_FORMAT "bx_%s_gui.dll" #define IMG_PLUGIN_FILENAME_FORMAT "bx_%s_img.dll" #define NET_PLUGIN_FILENAME_FORMAT "bx_eth_%s.dll" #define SND_PLUGIN_FILENAME_FORMAT "bx_sound%s.dll" #endif logfunctions *pluginlog; extern "C" { void (*pluginRegisterIRQ)(unsigned irq, const char* name) = 0; void (*pluginUnregisterIRQ)(unsigned irq, const char* name) = 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 (*pluginUnregisterIOReadHandler)(void *thisPtr, ioReadHandler_t callback, unsigned base, Bit8u mask) = 0; int (*pluginUnregisterIOWriteHandler)(void *thisPtr, ioWriteHandler_t callback, unsigned base, Bit8u mask) = 0; int (*pluginRegisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback, unsigned base, unsigned end, const char *name, Bit8u mask) = 0; int (*pluginRegisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback, unsigned base, unsigned end, const char *name, Bit8u mask) = 0; int (*pluginUnregisterIOReadHandlerRange)(void *thisPtr, ioReadHandler_t callback, unsigned begin, unsigned end, Bit8u mask) = 0; int (*pluginUnregisterIOWriteHandlerRange)(void *thisPtr, ioWriteHandler_t callback, unsigned begin, unsigned end, 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; void (*pluginHRQHackCallback)(void); unsigned pluginHRQ = 0; plugin_t *plugins = NULL; /* Head of the linked list of plugins */ device_t *devices = NULL; /* Head of the linked list of registered devices */ device_t *core_devices = NULL; /* Head of the linked list of registered core devices */ plugin_t *current_plugin_context = NULL; /************************************************************************/ /* Builtins declarations */ /************************************************************************/ static void builtinRegisterIRQ(unsigned irq, const char* name) { bx_devices.register_irq(irq, name); } static void builtinUnregisterIRQ(unsigned irq, const char* name) { bx_devices.unregister_irq(irq, name); } static void builtinSetHRQ(unsigned val) { pluginHRQ = val; } static void builtinSetHRQHackCallback(void (*callback)(void)) { pluginHRQHackCallback = callback; } static int builtinRegisterIOReadHandler(void *thisPtr, ioReadHandler_t callback, unsigned base, const char *name, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = 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 ret; } static int builtinRegisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback, unsigned base, const char *name, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = 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 ret; } static int builtinUnregisterIOReadHandler(void *thisPtr, ioReadHandler_t callback, unsigned base, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = bx_devices.unregister_io_read_handler (thisPtr, callback, base, mask); pluginlog->ldebug("plugin unregistered I/O read address at %04x", base); return ret; } static int builtinUnregisterIOWriteHandler(void *thisPtr, ioWriteHandler_t callback, unsigned base, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = bx_devices.unregister_io_write_handler (thisPtr, callback, base, mask); pluginlog->ldebug("plugin unregistered I/O write address at %04x", base); return ret; } static int builtinRegisterIOReadHandlerRange(void *thisPtr, ioReadHandler_t callback, unsigned base, unsigned end, const char *name, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = bx_devices.register_io_read_handler_range (thisPtr, callback, base, end, name, mask); pluginlog->ldebug("plugin %s registered I/O read addresses %04x to %04x", name, base, end); return ret; } static int builtinRegisterIOWriteHandlerRange(void *thisPtr, ioWriteHandler_t callback, unsigned base, unsigned end, const char *name, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = bx_devices.register_io_write_handler_range (thisPtr, callback, base, end, name, mask); pluginlog->ldebug("plugin %s registered I/O write addresses %04x to %04x", name, base, end); return ret; } static int builtinUnregisterIOReadHandlerRange(void *thisPtr, ioReadHandler_t callback, unsigned begin, unsigned end, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = bx_devices.unregister_io_read_handler_range (thisPtr, callback, begin, end, mask); pluginlog->ldebug("plugin unregistered I/O read addresses %04x to %04x", begin, end); return ret; } static int builtinUnregisterIOWriteHandlerRange(void *thisPtr, ioWriteHandler_t callback, unsigned begin, unsigned end, Bit8u mask) { int ret; BX_ASSERT(mask<8); ret = bx_devices.unregister_io_write_handler_range (thisPtr, callback, begin, end, mask); pluginlog->ldebug("plugin unregistered I/O write addresses %04x to %04x", begin, end); return ret; } 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; } #if BX_PLUGINS /************************************************************************/ /* Search for all available plugins */ /************************************************************************/ void plugin_add_entry(char *pgn_name, Bit16u type, Bit8u flags) { plugin_t *plugin, *temp; if ((type & PLUGTYPE_GUI) > 0) { if (!strncmp(pgn_name + strlen(pgn_name) - 4, "_gui", 4)) { pgn_name[strlen(pgn_name) - 4] = 0; } } else if (type == PLUGTYPE_IMG) { if (!strncmp(pgn_name + strlen(pgn_name) - 4, "_img", 4)) { pgn_name[strlen(pgn_name) - 4] = 0; } } else if (type == PLUGTYPE_NET) { if (!strncmp(pgn_name, "eth_", 4)) { memmove(pgn_name, pgn_name + 4, strlen(pgn_name) - 3); } } else if (type == PLUGTYPE_SND) { if (!strncmp(pgn_name, "sound", 5)) { memmove(pgn_name, pgn_name + 5, strlen(pgn_name) - 4); } } plugin = new plugin_t; plugin->type = type; plugin->flags = flags; plugin->name = pgn_name; plugin->loadtype = PLUGTYPE_NULL; plugin->initialized = 0; /* Insert plugin at the _end_ of the plugin linked list. */ plugin->next = NULL; if (plugins == NULL) { /* Empty list, this become the first entry. */ plugins = plugin; } else { /* Non-empty list. Add to end. */ temp = plugins; while (temp->next) temp = temp->next; temp->next = plugin; } } void plugins_search(void) { int nlen, flen1, flen2; char *fmtptr, *ltdl_path_var, *pgn_name, *pgn_path, *ptr; char fmtstr[32]; #ifndef WIN32 const char *path_sep = ":"; DIR *dir; struct dirent *dent; lt_dlhandle handle; #else const char *path_sep = ";"; WIN32_FIND_DATA finddata; HANDLE hFind; char filter[MAX_PATH]; char path[MAX_PATH]; HINSTANCE handle; #endif char tmpname[BX_PATHNAME_LEN]; plugin_entry_t plugin_entry; Bit16u type; Bit8u flags; #ifndef WIN32 setlocale(LC_ALL, "en_US"); #endif ltdl_path_var = getenv("LTDL_LIBRARY_PATH"); sprintf(fmtstr, PLUGIN_FILENAME_FORMAT, "*"); fmtptr = strchr(fmtstr, '*'); flen1 = fmtptr - fmtstr; flen2 = strlen(fmtstr) - flen1 - 1; if (ltdl_path_var != NULL) { pgn_path = new char[strlen(ltdl_path_var) + 1]; strcpy(pgn_path, ltdl_path_var); } else { pgn_path = new char[2]; strcpy(pgn_path, "."); } ptr = strtok(pgn_path, path_sep); while (ptr != NULL) { #ifndef WIN32 dir = opendir(ptr); if (dir != NULL) { while ((dent=readdir(dir)) != NULL) { nlen = strlen(dent->d_name); if ((!strncmp(dent->d_name, fmtstr, flen1)) && (!strcmp(dent->d_name + nlen - flen2, fmtptr + 1))) { pgn_name = new char[nlen - flen1 - flen2 + 1]; strncpy(pgn_name, dent->d_name + flen1, nlen - flen1 - flen2); pgn_name[nlen - flen1 - flen2] = 0; handle = lt_dlopen(dent->d_name); if (handle) { sprintf(tmpname, PLUGIN_ENTRY_FMT_STRING, pgn_name); plugin_entry = (plugin_entry_t) lt_dlsym(handle, tmpname); if (plugin_entry != NULL) { type = (Bit16u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_PROBE); flags = (Bit8u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_FLAGS); plugin_add_entry(pgn_name, type, flags); } lt_dlclose(handle); } else { delete [] pgn_name; } } } closedir(dir); } #else sprintf(filter, "%s\\*.dll", ptr); hFind = FindFirstFile(filter, &finddata); if (hFind != INVALID_HANDLE_VALUE) { do { nlen = lstrlen(finddata.cFileName); if ((!strncmp(finddata.cFileName, fmtstr, flen1)) && (!strcmp(finddata.cFileName + nlen - flen2, fmtptr + 1))) { pgn_name = new char[nlen - flen1 - flen2 + 1]; strncpy(pgn_name, finddata.cFileName + flen1, nlen - flen1 - flen2); pgn_name[nlen - flen1 - flen2] = 0; sprintf(path, "%s\\%s", ptr, finddata.cFileName); handle = LoadLibrary(path); if (handle) { sprintf(tmpname, PLUGIN_ENTRY_FMT_STRING, pgn_name); plugin_entry = (plugin_entry_t) GetProcAddress(handle, tmpname); if (plugin_entry != NULL) { type = (Bit16u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_PROBE); flags = (Bit8u) plugin_entry(NULL, PLUGTYPE_NULL, PLUGIN_FLAGS); plugin_add_entry(pgn_name, type, flags); } FreeLibrary(handle); } } } while (FindNextFile(hFind, &finddata)); FindClose(hFind); } #endif ptr = strtok(NULL, ":"); } delete [] pgn_path; } Bit8u bx_get_plugins_count(Bit16u type) { plugin_t *temp; Bit8u count = 0; if (plugins != NULL) { temp = plugins; while (temp != NULL) { if ((type & temp->type) != 0) count++; temp = temp->next; } } return count; } const char* bx_get_plugin_name(Bit16u type, Bit8u index) { plugin_t *temp; int count = 0; if (plugins != NULL) { temp = plugins; while (temp != NULL) { if ((type & temp->type) != 0) { if (count == index) return temp->name; count++; } temp = temp->next; } } return NULL; } Bit8u bx_get_plugin_flags(Bit16u type, Bit8u index) { plugin_t *temp; int count = 0; if (plugins != NULL) { temp = plugins; while (temp != NULL) { if ((type & temp->type) != 0) { if (count == index) return temp->flags; count++; } temp = temp->next; } } return 0; } /************************************************************************/ /* Plugin initialization / deinitialization */ /************************************************************************/ bool plugin_init_one(plugin_t *plugin) { /* initialize the plugin */ if (plugin->plugin_entry(plugin, plugin->loadtype, PLUGIN_INIT)) { pluginlog->info("Plugin initialization failed for %s", plugin->name); plugin_abort(plugin); return 0; } plugin->initialized = 1; return 1; } bool plugin_unload(plugin_t *plugin) { if (plugin->loadtype != PLUGTYPE_NULL) { if (plugin->initialized) plugin->plugin_entry(plugin, plugin->type, PLUGIN_FINI); #if defined(WIN32) FreeLibrary(plugin->handle); #else lt_dlclose(plugin->handle); #endif plugin->loadtype = PLUGTYPE_NULL; return 1; } else { return 0; } } bool plugin_load(const char *name, Bit16u type) { plugin_t *plugin = NULL, *temp; #if defined(WIN32) char dll_path_list[MAX_PATH]; #endif if (plugins != NULL) { temp = plugins; while (temp != NULL) { if (!strcmp(name, temp->name) && ((type & temp->type) != 0)) { if (temp->loadtype != PLUGTYPE_NULL) { BX_PANIC(("plugin '%s' already loaded", name)); return 0; } else { plugin = temp; break; } } temp = temp->next; } } if (plugin == NULL) { BX_PANIC(("plugin '%s' not found", name)); return 0; } char plugin_filename[BX_PATHNAME_LEN], tmpname[BX_PATHNAME_LEN]; if (type == PLUGTYPE_GUI) { sprintf(tmpname, GUI_PLUGIN_FILENAME_FORMAT, name); } else if (type == PLUGTYPE_IMG) { sprintf(tmpname, IMG_PLUGIN_FILENAME_FORMAT, name); } else if (type == PLUGTYPE_NET) { sprintf(tmpname, NET_PLUGIN_FILENAME_FORMAT, name); } else if (type == PLUGTYPE_SND) { sprintf(tmpname, SND_PLUGIN_FILENAME_FORMAT, name); } else { sprintf(tmpname, PLUGIN_FILENAME_FORMAT, name); } sprintf(plugin_filename, "%s%s", PLUGIN_PATH, tmpname); // 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_entry. BX_ASSERT(current_plugin_context == NULL); current_plugin_context = plugin; #if defined(WIN32) char *ptr; plugin->handle = LoadLibrary(plugin_filename); if (!plugin->handle) { if (GetEnvironmentVariable("LTDL_LIBRARY_PATH", dll_path_list, MAX_PATH)) { ptr = strtok(dll_path_list, ";"); while ((ptr) && !plugin->handle) { sprintf(plugin_filename, "%s\\%s", ptr, tmpname); plugin->handle = LoadLibrary(plugin_filename); ptr = strtok(NULL, ";"); } } } BX_INFO(("DLL handle is %p", plugin->handle)); if (!plugin->handle) { current_plugin_context = NULL; BX_PANIC(("LoadLibrary failed for module '%s' (%s): error=%d", name, plugin_filename, GetLastError())); return 0; } #else 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): %s", name, plugin_filename, lt_dlerror())); return 0; } #endif plugin->loadtype = type; if (type == PLUGTYPE_GUI) { sprintf(tmpname, GUI_PLUGIN_ENTRY_FMT_STRING, name); } else if (type == PLUGTYPE_IMG) { sprintf(tmpname, IMG_PLUGIN_ENTRY_FMT_STRING, name); } else if (type == PLUGTYPE_NET) { sprintf(tmpname, NET_PLUGIN_ENTRY_FMT_STRING, name); } else if (type == PLUGTYPE_SND) { sprintf(tmpname, SND_PLUGIN_ENTRY_FMT_STRING, name); } else { sprintf(tmpname, PLUGIN_ENTRY_FMT_STRING, name); } #if defined(WIN32) plugin->plugin_entry = (plugin_entry_t) GetProcAddress(plugin->handle, tmpname); if (plugin->plugin_entry == NULL) { pluginlog->panic("could not find plugin_entry for module '%s' (%s): error=%d", name, plugin_filename, GetLastError()); plugin_abort(plugin); return 0; } #else plugin->plugin_entry = (plugin_entry_t) lt_dlsym(plugin->handle, tmpname); if (plugin->plugin_entry == NULL) { pluginlog->panic("could not find plugin_entry for module '%s' (%s): %s", name, plugin_filename, lt_dlerror()); plugin_abort(plugin); return 0; } #endif pluginlog->info("loaded plugin %s",plugin_filename); if (!plugin_init_one(plugin)) { return 0; } // 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 1; } void plugin_abort(plugin_t *plugin) { plugin_unload(plugin); pluginlog->panic("loading plugin '%s' aborted", plugin->name); } #endif /* end of #if BX_PLUGINS */ /************************************************************************/ /* Plugin system: initialisation of plugins entry points */ /************************************************************************/ void plugin_startup(void) { pluginRegisterIRQ = builtinRegisterIRQ; pluginUnregisterIRQ = builtinUnregisterIRQ; pluginSetHRQHackCallback = builtinSetHRQHackCallback; pluginSetHRQ = builtinSetHRQ; pluginRegisterIOReadHandler = builtinRegisterIOReadHandler; pluginRegisterIOWriteHandler = builtinRegisterIOWriteHandler; pluginUnregisterIOReadHandler = builtinUnregisterIOReadHandler; pluginUnregisterIOWriteHandler = builtinUnregisterIOWriteHandler; pluginRegisterIOReadHandlerRange = builtinRegisterIOReadHandlerRange; pluginRegisterIOWriteHandlerRange = builtinRegisterIOWriteHandlerRange; pluginUnregisterIOReadHandlerRange = builtinUnregisterIOReadHandlerRange; pluginUnregisterIOWriteHandlerRange = builtinUnregisterIOWriteHandlerRange; pluginRegisterDefaultIOReadHandler = builtinRegisterDefaultIOReadHandler; pluginRegisterDefaultIOWriteHandler = builtinRegisterDefaultIOWriteHandler; pluginlog = new logfunctions(); pluginlog->put("PLUGIN"); #if BX_PLUGINS #if !defined(WIN32) 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 plugins_search(); #endif } void plugin_cleanup(void) { #if BX_PLUGINS plugin_t *dead_plug; while (plugins != NULL) { if (plugins->loadtype != PLUGTYPE_NULL) { plugin_unload(plugins); } delete [] plugins->name; dead_plug = plugins; plugins = plugins->next; delete dead_plug; } #endif } /************************************************************************/ /* Plugin system: Device registration */ /************************************************************************/ void pluginRegisterDeviceDevmodel(plugin_t *plugin, Bit16u type, bx_devmodel_c *devmodel, const char *name) { device_t **devlist; device_t *device = new device_t; device->name = name; BX_ASSERT(devmodel != NULL); device->devmodel = devmodel; device->plugin = plugin; // this can be NULL device->next = NULL; device->plugtype = type; switch (type) { case PLUGTYPE_CORE: case PLUGTYPE_VGA: devlist = &core_devices; break; case PLUGTYPE_STANDARD: case PLUGTYPE_OPTIONAL: default: devlist = &devices; break; } if (!*devlist) { /* Empty list, this become the first entry. */ *devlist = device; } else { /* Non-empty list. Add to end. */ device_t *temp = *devlist; while (temp->next) temp = temp->next; temp->next = device; } } /************************************************************************/ /* Plugin system: Remove registered plugin device */ /************************************************************************/ void pluginUnregisterDeviceDevmodel(const char *name, Bit16u type) { device_t **devlist; device_t *device, *prev = NULL; switch (type) { case PLUGTYPE_CORE: case PLUGTYPE_VGA: devlist = &core_devices; break; case PLUGTYPE_STANDARD: case PLUGTYPE_OPTIONAL: default: devlist = &devices; break; } for (device = *devlist; device; device = device->next) { if (!strcmp(name, device->name)) { if (prev == NULL) { *devlist = device->next; } else { prev->next = device->next; } delete device; break; } else { prev = device; } } } /************************************************************************/ /* Plugin system: Check if a plugin is loaded */ /************************************************************************/ bool pluginDevicePresent(const char *name) { device_t *device; for (device = devices; device; device = device->next) { if (!strcmp(name, device->name)) return 1; } return 0; } #if BX_PLUGINS /************************************************************************/ /* Plugin system: Load one plugin */ /************************************************************************/ bool bx_load_plugin(const char *name, Bit16u type) { plugin_t *plugin; if (!strcmp(name, "*")) { for (plugin = plugins; plugin; plugin = plugin->next) { if (((type & plugin->type) != 0) && (plugin->loadtype == PLUGTYPE_NULL)) { plugin_load(plugin->name, type); } } return 1; } else { return plugin_load(name, type); } } bool bx_unload_plugin(const char *name, bool devflag) { plugin_t *plugin; bool ret = 0; for (plugin = plugins; plugin; plugin = plugin->next) { if (!strcmp(plugin->name, name)) { if (devflag) { pluginUnregisterDeviceDevmodel(plugin->name, plugin->type); } ret = plugin_unload(plugin); break; } } return ret; } void bx_unload_plugin_type(const char *name, Bit16u type) { plugin_t *plugin; for (plugin = plugins; plugin; plugin = plugin->next) { if (!strcmp(plugin->name, name) && ((plugin->type & type) != 0)) { plugin_unload(plugin); break; } } } #endif /* end of #if BX_PLUGINS */ /*************************************************************************/ /* Plugin system: Execute init function of all registered plugin-devices */ /*************************************************************************/ void bx_init_plugins() { device_t *device; for (device = core_devices; device; device = device->next) { pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name); device->devmodel->init(); } for (device = devices; device; device = device->next) { if (device->plugtype == PLUGTYPE_STANDARD) { pluginlog->info("init_dev of '%s' plugin device by virtual method",device->name); device->devmodel->init(); } } for (device = devices; device; device = device->next) { if (device->plugtype == PLUGTYPE_OPTIONAL) { 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 = core_devices; device; device = device->next) { pluginlog->info("reset of '%s' plugin device by virtual method",device->name); device->devmodel->reset(signal); } for (device = devices; device; device = device->next) { if (device->plugtype == PLUGTYPE_STANDARD) { pluginlog->info("reset of '%s' plugin device by virtual method",device->name); device->devmodel->reset(signal); } } for (device = devices; device; device = device->next) { if (device->plugtype == PLUGTYPE_OPTIONAL) { pluginlog->info("reset of '%s' plugin device by virtual method",device->name); device->devmodel->reset(signal); } } } /*******************************************************/ /* Plugin system: Unload all registered plugin-devices */ /*******************************************************/ void bx_unload_plugins() { device_t *device, *next; // unload non-core plugins first device = devices; while (device != NULL) { if (device->plugin != NULL) { #if BX_PLUGINS bx_unload_plugin(device->name, 0); #endif } else { #if !BX_PLUGINS if (!bx_unload_opt_plugin(device->name, 0)) { delete device->devmodel; } #endif } next = device->next; delete device; device = next; } devices = NULL; // now it's safe to unload core plugins device = core_devices; while (device != NULL) { if (device->plugin != NULL) { #if BX_PLUGINS bx_unload_plugin(device->name, 0); #endif } else { delete device->devmodel; } next = device->next; delete device; device = next; } core_devices = NULL; } /**************************************************************************/ /* Plugin system: Register device state of all registered plugin-devices */ /**************************************************************************/ void bx_plugins_register_state() { device_t *device; for (device = core_devices; device; device = device->next) { pluginlog->info("register state of '%s' plugin device by virtual method",device->name); device->devmodel->register_state(); } for (device = devices; device; device = device->next) { pluginlog->info("register state of '%s' plugin device by virtual method",device->name); device->devmodel->register_state(); } } /***************************************************************************/ /* Plugin system: Execute code after restoring state of all plugin devices */ /***************************************************************************/ void bx_plugins_after_restore_state() { device_t *device; for (device = core_devices; device; device = device->next) { device->devmodel->after_restore_state(); } for (device = devices; device; device = device->next) { if (device->plugtype == PLUGTYPE_STANDARD) { device->devmodel->after_restore_state(); } } for (device = devices; device; device = device->next) { if (device->plugtype == PLUGTYPE_OPTIONAL) { device->devmodel->after_restore_state(); } } } #if !BX_PLUGINS // Special code for handling modules when plugin support is turned off. #define BUILTIN_OPT_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_OPTIONAL, 0, lib##mod##_plugin_entry, 0} #define BUILTIN_OPTPCI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_OPTIONAL, PLUGFLAG_PCI, lib##mod##_plugin_entry, 0} #define BUILTIN_VGA_PLUGIN_ENTRY(mod, t, f) {#mod, PLUGTYPE_VGA | t, f, lib##mod##_plugin_entry, 0} #define BUILTIN_CI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_CI, 0, lib##mod##_plugin_entry, 0} #define BUILTIN_GUI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_GUI, 0, lib##mod##_gui_plugin_entry, 0} #define BUILTIN_GUICI_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_GUI | PLUGTYPE_CI, 0, lib##mod##_gui_plugin_entry, 0} #define BUILTIN_IMG_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_IMG, 0, lib##mod##_img_plugin_entry, 0} #define BUILTIN_NET_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_NET, 0, libeth_##mod##_plugin_entry, 0} #define BUILTIN_SND_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_SND, 0, libsound##mod##_plugin_entry, 0} #define BUILTIN_USB_PLUGIN_ENTRY(mod) {#mod, PLUGTYPE_USB, 0, lib##mod##_plugin_entry, 0} plugin_t bx_builtin_plugins[] = { #if BX_USE_TEXTCONFIG BUILTIN_CI_PLUGIN_ENTRY(textconfig), #endif #if BX_USE_WIN32CONFIG BUILTIN_CI_PLUGIN_ENTRY(win32config), #endif #if BX_WITH_AMIGAOS BUILTIN_GUI_PLUGIN_ENTRY(amigaos), #endif #if BX_WITH_CARBON BUILTIN_GUI_PLUGIN_ENTRY(carbon), #endif #if BX_WITH_MACOS BUILTIN_GUI_PLUGIN_ENTRY(macos), #endif #if BX_WITH_NOGUI BUILTIN_GUI_PLUGIN_ENTRY(nogui), #endif #if BX_WITH_RFB BUILTIN_GUI_PLUGIN_ENTRY(rfb), #endif #if BX_WITH_SDL BUILTIN_GUI_PLUGIN_ENTRY(sdl), #endif #if BX_WITH_SDL2 BUILTIN_GUI_PLUGIN_ENTRY(sdl2), #endif #if BX_WITH_TERM BUILTIN_GUI_PLUGIN_ENTRY(term), #endif #if BX_WITH_VNCSRV BUILTIN_GUI_PLUGIN_ENTRY(vncsrv), #endif #if BX_WITH_WIN32 BUILTIN_GUI_PLUGIN_ENTRY(win32), #endif #if BX_WITH_WX BUILTIN_GUICI_PLUGIN_ENTRY(wx), #endif #if BX_WITH_X11 BUILTIN_GUI_PLUGIN_ENTRY(x), #endif BUILTIN_VGA_PLUGIN_ENTRY(vga, 0, PLUGFLAG_PCI), #if BX_SUPPORT_CLGD54XX BUILTIN_VGA_PLUGIN_ENTRY(svga_cirrus, 0, PLUGFLAG_PCI), #endif #if BX_SUPPORT_VOODOO BUILTIN_VGA_PLUGIN_ENTRY(voodoo, PLUGTYPE_OPTIONAL, PLUGFLAG_PCI), #endif BUILTIN_OPT_PLUGIN_ENTRY(unmapped), BUILTIN_OPT_PLUGIN_ENTRY(biosdev), BUILTIN_OPT_PLUGIN_ENTRY(speaker), BUILTIN_OPT_PLUGIN_ENTRY(extfpuirq), BUILTIN_OPT_PLUGIN_ENTRY(parallel), BUILTIN_OPT_PLUGIN_ENTRY(serial), #if BX_SUPPORT_BUSMOUSE BUILTIN_OPT_PLUGIN_ENTRY(busmouse), #endif #if BX_SUPPORT_E1000 BUILTIN_OPTPCI_PLUGIN_ENTRY(e1000), #endif #if BX_SUPPORT_ES1370 BUILTIN_OPTPCI_PLUGIN_ENTRY(es1370), #endif #if BX_SUPPORT_GAMEPORT BUILTIN_OPT_PLUGIN_ENTRY(gameport), #endif #if BX_SUPPORT_IODEBUG BUILTIN_OPT_PLUGIN_ENTRY(iodebug), #endif #if BX_SUPPORT_NE2K BUILTIN_OPTPCI_PLUGIN_ENTRY(ne2k), #endif #if BX_SUPPORT_PCIDEV BUILTIN_OPTPCI_PLUGIN_ENTRY(pcidev), #endif #if BX_SUPPORT_PCIPNIC BUILTIN_OPTPCI_PLUGIN_ENTRY(pcipnic), #endif #if BX_SUPPORT_SB16 BUILTIN_OPT_PLUGIN_ENTRY(sb16), #endif #if BX_SUPPORT_USB_UHCI BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_uhci), #endif #if BX_SUPPORT_USB_OHCI BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_ohci), #endif #if BX_SUPPORT_USB_EHCI BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_ehci), #endif #if BX_SUPPORT_USB_XHCI BUILTIN_OPTPCI_PLUGIN_ENTRY(usb_xhci), #endif #if BX_SUPPORT_SOUNDLOW BUILTIN_SND_PLUGIN_ENTRY(dummy), BUILTIN_SND_PLUGIN_ENTRY(file), #if BX_HAVE_SOUND_ALSA BUILTIN_SND_PLUGIN_ENTRY(alsa), #endif #if BX_HAVE_SOUND_OSS BUILTIN_SND_PLUGIN_ENTRY(oss), #endif #if BX_HAVE_SOUND_OSX BUILTIN_SND_PLUGIN_ENTRY(osx), #endif #if BX_HAVE_SOUND_SDL BUILTIN_SND_PLUGIN_ENTRY(sdl), #endif #if BX_HAVE_SOUND_WIN BUILTIN_SND_PLUGIN_ENTRY(win), #endif #endif #if BX_NETWORKING BUILTIN_NET_PLUGIN_ENTRY(null), BUILTIN_NET_PLUGIN_ENTRY(vnet), #if BX_NETMOD_FBSD BUILTIN_NET_PLUGIN_ENTRY(fbsd), #endif #if BX_NETMOD_LINUX BUILTIN_NET_PLUGIN_ENTRY(linux), #endif #if BX_NETMOD_SLIRP BUILTIN_NET_PLUGIN_ENTRY(slirp), #endif #if BX_NETMOD_SOCKET BUILTIN_NET_PLUGIN_ENTRY(socket), #endif #if BX_NETMOD_TAP BUILTIN_NET_PLUGIN_ENTRY(tap), #endif #if BX_NETMOD_TUNTAP BUILTIN_NET_PLUGIN_ENTRY(tuntap), #endif #if BX_NETMOD_VDE BUILTIN_NET_PLUGIN_ENTRY(vde), #endif #if BX_NETMOD_WIN32 BUILTIN_NET_PLUGIN_ENTRY(win32), #endif #endif #if BX_SUPPORT_PCIUSB BUILTIN_USB_PLUGIN_ENTRY(usb_floppy), BUILTIN_USB_PLUGIN_ENTRY(usb_hid), BUILTIN_USB_PLUGIN_ENTRY(usb_hub), BUILTIN_USB_PLUGIN_ENTRY(usb_msd), BUILTIN_USB_PLUGIN_ENTRY(usb_printer), #endif BUILTIN_IMG_PLUGIN_ENTRY(vmware3), BUILTIN_IMG_PLUGIN_ENTRY(vmware4), BUILTIN_IMG_PLUGIN_ENTRY(vbox), BUILTIN_IMG_PLUGIN_ENTRY(vpc), BUILTIN_IMG_PLUGIN_ENTRY(vvfat), {"NULL", PLUGTYPE_NULL, 0, NULL, 0} }; Bit8u bx_get_plugins_count_np(Bit16u type) { int i = 0; Bit8u count = 0; while (strcmp(bx_builtin_plugins[i].name, "NULL")) { if ((type & bx_builtin_plugins[i].type) != 0) count++; i++; } return count; } const char* bx_get_plugin_name_np(Bit16u type, Bit8u index) { int i = 0; Bit8u count = 0; while (strcmp(bx_builtin_plugins[i].name, "NULL")) { if ((type & bx_builtin_plugins[i].type) != 0) { if (count == index) return bx_builtin_plugins[i].name; count++; } i++; } return NULL; } Bit8u bx_get_plugin_flags_np(Bit16u type, Bit8u index) { int i = 0; Bit8u count = 0; while (strcmp(bx_builtin_plugins[i].name, "NULL")) { if ((type & bx_builtin_plugins[i].type) != 0) { if (count == index) return bx_builtin_plugins[i].flags; count++; } i++; } return 0; } int bx_load_plugin_np(const char *name, Bit16u type) { int i = 0; while (strcmp(bx_builtin_plugins[i].name, "NULL")) { if ((!strcmp(name, bx_builtin_plugins[i].name)) && ((type & bx_builtin_plugins[i].type) != 0)) { if (bx_builtin_plugins[i].initialized == 0) { bx_builtin_plugins[i].loadtype = type; bx_builtin_plugins[i].plugin_entry(NULL, type, PLUGIN_INIT); bx_builtin_plugins[i].initialized = 1; } return 1; } i++; } return 0; } int bx_unload_opt_plugin(const char *name, bool devflag) { int i = 0; while (strcmp(bx_builtin_plugins[i].name, "NULL")) { if ((!strcmp(name, bx_builtin_plugins[i].name)) && ((bx_builtin_plugins[i].type == PLUGTYPE_OPTIONAL) || (bx_builtin_plugins[i].type == PLUGTYPE_VGA))) { if (bx_builtin_plugins[i].initialized == 1) { if (devflag) { pluginUnregisterDeviceDevmodel(bx_builtin_plugins[i].name, bx_builtin_plugins[i].type); } bx_builtin_plugins[i].plugin_entry(NULL, bx_builtin_plugins[i].loadtype, PLUGIN_FINI); bx_builtin_plugins[i].loadtype = PLUGTYPE_NULL; bx_builtin_plugins[i].initialized = 0; } return 1; } i++; } return 0; } #endif }