1 /////////////////////////////////////////////////////////////////////////
2 // $Id: plugin.cc,v 1.21 2006/09/16 14:47:40 vruppert Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // This file defines the plugin and plugin-device registration functions and
6 // the device registration functions. It handles dynamic loading of modules,
7 // using the LTDL library for cross-platform support.
9 // This file is based on the plugin.c file from plex86, but with significant
10 // changes to make it work in Bochs.
11 // Plex86 is Copyright (C) 1999-2000 The plex86 developers team
13 /////////////////////////////////////////////////////////////////////////
16 #include "iodev/iodev.h"
19 #define LOG_THIS genlog->
21 #define PLUGIN_INIT_FMT_STRING "lib%s_LTX_plugin_init"
22 #define PLUGIN_FINI_FMT_STRING "lib%s_LTX_plugin_fini"
23 #define PLUGIN_PATH ""
26 #define PLUGIN_FILENAME_FORMAT "libbx_%s.la"
28 #define PLUGIN_FILENAME_FORMAT "bx_%s.dll"
33 void (*pluginRegisterIRQ
)(unsigned irq
, const char* name
) = 0;
34 void (*pluginUnregisterIRQ
)(unsigned irq
, const char* name
) = 0;
36 void (*pluginSetHRQ
)(unsigned val
) = 0;
37 void (*pluginSetHRQHackCallback
)( void (*callback
)(void) ) = 0;
39 int (*pluginRegisterIOReadHandler
)(void *thisPtr
, ioReadHandler_t callback
,
40 unsigned base
, const char *name
, Bit8u mask
) = 0;
41 int (*pluginRegisterIOWriteHandler
)(void *thisPtr
, ioWriteHandler_t callback
,
42 unsigned base
, const char *name
, Bit8u mask
) = 0;
43 int (*pluginUnregisterIOReadHandler
)(void *thisPtr
, ioReadHandler_t callback
,
44 unsigned base
, Bit8u mask
) = 0;
45 int (*pluginUnregisterIOWriteHandler
)(void *thisPtr
, ioWriteHandler_t callback
,
46 unsigned base
, Bit8u mask
) = 0;
47 int (*pluginRegisterIOReadHandlerRange
)(void *thisPtr
, ioReadHandler_t callback
,
48 unsigned base
, unsigned end
, const char *name
, Bit8u mask
) = 0;
49 int (*pluginRegisterIOWriteHandlerRange
)(void *thisPtr
, ioWriteHandler_t callback
,
50 unsigned base
, unsigned end
, const char *name
, Bit8u mask
) = 0;
51 int (*pluginUnregisterIOReadHandlerRange
)(void *thisPtr
, ioReadHandler_t callback
,
52 unsigned begin
, unsigned end
, Bit8u mask
) = 0;
53 int (*pluginUnregisterIOWriteHandlerRange
)(void *thisPtr
, ioWriteHandler_t callback
,
54 unsigned begin
, unsigned end
, Bit8u mask
) = 0;
55 int (*pluginRegisterDefaultIOReadHandler
)(void *thisPtr
, ioReadHandler_t callback
,
56 const char *name
, Bit8u mask
) = 0;
57 int (*pluginRegisterDefaultIOWriteHandler
)(void *thisPtr
, ioWriteHandler_t callback
,
58 const char *name
, Bit8u mask
) = 0;
59 int (*pluginRegisterTimer
)(void *this_ptr
, void (*funct
)(void *),
60 Bit32u useconds
, bx_bool continuous
,
61 bx_bool active
, const char* name
) = 0;
62 void (*pluginActivateTimer
)(unsigned id
, Bit32u usec
, bx_bool continuous
) = 0;
64 void (*pluginHRQHackCallback
)(void);
65 unsigned pluginHRQ
= 0;
67 plugin_t
*plugins
= NULL
; /* Head of the linked list of plugins */
69 static void plugin_init_one(plugin_t
*plugin
);
72 device_t
*devices
= NULL
; /* Head of the linked list of registered devices */
74 plugin_t
*current_plugin_context
= NULL
;
76 /************************************************************************/
77 /* Builtins declarations */
78 /************************************************************************/
81 builtinRegisterIRQ(unsigned irq
, const char* name
)
84 pluginlog
->panic("builtinRegisterIRQ called, no pic plugin loaded?");
86 bx_devices
.register_irq(irq
, name
);
91 builtinUnregisterIRQ(unsigned irq
, const char* name
)
94 pluginlog
->panic("builtinUnregisterIRQ called, no pic plugin loaded?");
96 bx_devices
.unregister_irq(irq
, name
);
101 builtinSetHRQ(unsigned val
)
104 pluginlog
->panic("builtinSetHRQ called, no plugin loaded?");
111 builtinSetHRQHackCallback( void (*callback
)(void) )
114 pluginlog
->panic("builtinSetHRQHackCallback called, no plugin loaded?");
116 pluginHRQHackCallback
= callback
;
121 builtinRegisterIOReadHandler(void *thisPtr
, ioReadHandler_t callback
,
122 unsigned base
, const char *name
, Bit8u mask
)
126 ret
= bx_devices
.register_io_read_handler (thisPtr
, callback
, base
, name
, mask
);
127 pluginlog
->ldebug("plugin %s registered I/O read address at %04x", name
, base
);
132 builtinRegisterIOWriteHandler(void *thisPtr
, ioWriteHandler_t callback
,
133 unsigned base
, const char *name
, Bit8u mask
)
137 ret
= bx_devices
.register_io_write_handler (thisPtr
, callback
, base
, name
, mask
);
138 pluginlog
->ldebug("plugin %s registered I/O write address at %04x", name
, base
);
143 builtinUnregisterIOReadHandler(void *thisPtr
, ioReadHandler_t callback
,
144 unsigned base
, Bit8u mask
)
148 ret
= bx_devices
.unregister_io_read_handler (thisPtr
, callback
, base
, mask
);
149 pluginlog
->ldebug("plugin unregistered I/O read address at %04x", base
);
154 builtinUnregisterIOWriteHandler(void *thisPtr
, ioWriteHandler_t callback
,
155 unsigned base
, Bit8u mask
)
159 ret
= bx_devices
.unregister_io_write_handler (thisPtr
, callback
, base
, mask
);
160 pluginlog
->ldebug("plugin unregistered I/O write address at %04x", base
);
165 builtinRegisterIOReadHandlerRange(void *thisPtr
, ioReadHandler_t callback
,
166 unsigned base
, unsigned end
, const char *name
, Bit8u mask
)
170 ret
= bx_devices
.register_io_read_handler_range (thisPtr
, callback
, base
, end
, name
, mask
);
171 pluginlog
->ldebug("plugin %s registered I/O read addresses %04x to %04x", name
, base
, end
);
176 builtinRegisterIOWriteHandlerRange(void *thisPtr
, ioWriteHandler_t callback
,
177 unsigned base
, unsigned end
, const char *name
, Bit8u mask
)
181 ret
= bx_devices
.register_io_write_handler_range (thisPtr
, callback
, base
, end
, name
, mask
);
182 pluginlog
->ldebug("plugin %s registered I/O write addresses %04x to %04x", name
, base
, end
);
187 builtinUnregisterIOReadHandlerRange(void *thisPtr
, ioReadHandler_t callback
,
188 unsigned begin
, unsigned end
, Bit8u mask
)
192 ret
= bx_devices
.unregister_io_read_handler_range (thisPtr
, callback
, begin
, end
, mask
);
193 pluginlog
->ldebug("plugin unregistered I/O read addresses %04x to %04x", begin
, end
);
198 builtinUnregisterIOWriteHandlerRange(void *thisPtr
, ioWriteHandler_t callback
,
199 unsigned begin
, unsigned end
, Bit8u mask
)
203 ret
= bx_devices
.unregister_io_write_handler_range (thisPtr
, callback
, begin
, end
, mask
);
204 pluginlog
->ldebug("plugin unregistered I/O write addresses %04x to %04x", begin
, end
);
209 builtinRegisterDefaultIOReadHandler(void *thisPtr
, ioReadHandler_t callback
,
210 const char *name
, Bit8u mask
)
213 bx_devices
.register_default_io_read_handler (thisPtr
, callback
, name
, mask
);
214 pluginlog
->ldebug("plugin %s registered default I/O read ", name
);
219 builtinRegisterDefaultIOWriteHandler(void *thisPtr
, ioWriteHandler_t callback
,
220 const char *name
, Bit8u mask
)
223 bx_devices
.register_default_io_write_handler (thisPtr
, callback
, name
, mask
);
224 pluginlog
->ldebug("plugin %s registered default I/O write ", name
);
229 builtinRegisterTimer(void *this_ptr
, void (*funct
)(void *),
230 Bit32u useconds
, bx_bool continuous
,
231 bx_bool active
, const char* name
)
233 int id
= bx_pc_system
.register_timer (this_ptr
, funct
, useconds
, continuous
, active
, name
);
234 pluginlog
->ldebug("plugin %s registered timer %d", name
, id
);
239 builtinActivateTimer(unsigned id
, Bit32u usec
, bx_bool continuous
)
241 bx_pc_system
.activate_timer (id
, usec
, continuous
);
242 pluginlog
->ldebug("plugin activated timer %d", id
);
246 /************************************************************************/
247 /* Plugin initialization / deinitialization */
248 /************************************************************************/
251 plugin_init_all (void)
255 pluginlog
->info("Initializing plugins");
257 for (plugin
= plugins
; plugin
; plugin
= plugin
->next
)
259 char *arg_ptr
= plugin
->args
;
261 /* process the command line */
263 while (plugin
->argc
< MAX_ARGC
)
265 while (*arg_ptr
&& isspace (*arg_ptr
))
270 plugin
->argv
[plugin
->argc
++] = arg_ptr
;
272 while (*arg_ptr
&& !isspace (*arg_ptr
))
280 /* initialize the plugin */
281 if (plugin
->plugin_init (plugin
, plugin
->type
, plugin
->argc
, plugin
->argv
))
283 pluginlog
->panic("Plugin initialization failed for %s", plugin
->name
);
287 plugin
->initialized
= 1;
294 plugin_init_one(plugin_t
*plugin
)
296 char *arg_ptr
= plugin
->args
;
298 /* process the command line */
300 while (plugin
->argc
< MAX_ARGC
)
302 while (*arg_ptr
&& isspace (*arg_ptr
))
307 plugin
->argv
[plugin
->argc
++] = arg_ptr
;
309 while (*arg_ptr
&& !isspace (*arg_ptr
))
317 /* initialize the plugin */
318 if (plugin
->plugin_init (plugin
, plugin
->type
, plugin
->argc
, plugin
->argv
))
320 pluginlog
->info("Plugin initialization failed for %s", plugin
->name
);
324 plugin
->initialized
= 1;
328 plugin_t
*plugin_unload(plugin_t
*plugin
)
332 if (plugin
->initialized
)
333 plugin
->plugin_fini();
335 lt_dlclose(plugin
->handle
);
336 delete [] plugin
->name
;
339 plugin
= plugin
->next
;
346 void plugin_fini_all (void)
350 for (plugin
= plugins
; plugin
; plugin
= plugin_unload(plugin
));
355 void plugin_load(char *name
, char *args
, plugintype_t type
)
359 plugin
= (plugin_t
*)malloc (sizeof(plugin_t
));
362 BX_PANIC(("malloc plugin_t failed"));
368 plugin
->initialized
= 0;
370 char plugin_filename
[BX_PATHNAME_LEN
], buf
[BX_PATHNAME_LEN
];
371 sprintf(buf
, PLUGIN_FILENAME_FORMAT
, name
);
372 sprintf(plugin_filename
, "%s%s", PLUGIN_PATH
, buf
);
374 // Set context so that any devices that the plugin registers will
375 // be able to see which plugin created them. The registration will
376 // be called from either dlopen (global constructors) or plugin_init.
377 BX_ASSERT (current_plugin_context
== NULL
);
378 current_plugin_context
= plugin
;
379 plugin
->handle
= lt_dlopen (plugin_filename
);
380 BX_INFO (("lt_dlhandle is %p", plugin
->handle
));
383 current_plugin_context
= NULL
;
384 BX_PANIC (("dlopen failed for module '%s': %s", name
, lt_dlerror ()));
389 sprintf(buf
, PLUGIN_INIT_FMT_STRING
, name
);
390 plugin
->plugin_init
=
391 (int (*)(struct _plugin_t
*, enum plugintype_t
, int, char *[])) /* monster typecast */
392 lt_dlsym (plugin
->handle
, buf
);
393 if (plugin
->plugin_init
== NULL
) {
394 pluginlog
->panic("could not find plugin_init: %s", lt_dlerror ());
398 sprintf(buf
, PLUGIN_FINI_FMT_STRING
, name
);
399 plugin
->plugin_fini
= (void (*)(void)) lt_dlsym (plugin
->handle
, buf
);
400 if (plugin
->plugin_init
== NULL
) {
401 pluginlog
->panic("could not find plugin_fini: %s", lt_dlerror ());
404 pluginlog
->info("loaded plugin %s",plugin_filename
);
407 /* Insert plugin at the _end_ of the plugin linked list. */
412 /* Empty list, this become the first entry. */
417 /* Non-empty list. Add to end. */
418 plugin_t
*temp
= plugins
;
426 plugin_init_one(plugin
);
428 // check that context didn't change. This should only happen if we
429 // need a reentrant plugin_load.
430 BX_ASSERT (current_plugin_context
== plugin
);
431 current_plugin_context
= NULL
;
436 void plugin_abort(void)
438 pluginlog
->panic("plugin load aborted");
441 #endif /* end of #if BX_PLUGINS */
443 /************************************************************************/
444 /* Plugin system: initialisation of plugins entry points */
445 /************************************************************************/
450 pluginRegisterIRQ
= builtinRegisterIRQ
;
451 pluginUnregisterIRQ
= builtinUnregisterIRQ
;
453 pluginSetHRQHackCallback
= builtinSetHRQHackCallback
;
454 pluginSetHRQ
= builtinSetHRQ
;
456 pluginRegisterIOReadHandler
= builtinRegisterIOReadHandler
;
457 pluginRegisterIOWriteHandler
= builtinRegisterIOWriteHandler
;
459 pluginUnregisterIOReadHandler
= builtinUnregisterIOReadHandler
;
460 pluginUnregisterIOWriteHandler
= builtinUnregisterIOWriteHandler
;
462 pluginRegisterIOReadHandlerRange
= builtinRegisterIOReadHandlerRange
;
463 pluginRegisterIOWriteHandlerRange
= builtinRegisterIOWriteHandlerRange
;
465 pluginUnregisterIOReadHandlerRange
= builtinUnregisterIOReadHandlerRange
;
466 pluginUnregisterIOWriteHandlerRange
= builtinUnregisterIOWriteHandlerRange
;
468 pluginRegisterDefaultIOReadHandler
= builtinRegisterDefaultIOReadHandler
;
469 pluginRegisterDefaultIOWriteHandler
= builtinRegisterDefaultIOWriteHandler
;
471 pluginRegisterTimer
= builtinRegisterTimer
;
472 pluginActivateTimer
= builtinActivateTimer
;
475 pluginlog
= new logfunctions();
476 pluginlog
->put("PLGIN");
477 pluginlog
->settype(PLUGINLOG
);
478 int status
= lt_dlinit ();
480 BX_ERROR (("initialization error in ltdl library (for loading plugins)"));
481 BX_PANIC (("error message was: %s", lt_dlerror ()));
487 /************************************************************************/
488 /* Plugin system: Device registration */
489 /************************************************************************/
491 void pluginRegisterDeviceDevmodel(plugin_t
*plugin
, plugintype_t type
, bx_devmodel_c
*devmodel
, char *name
)
495 device
= (device_t
*)malloc (sizeof (device_t
));
498 pluginlog
->panic("can't allocate device_t");
502 BX_ASSERT (devmodel
!= NULL
);
503 device
->devmodel
= devmodel
;
504 device
->plugin
= plugin
; // this can be NULL
507 // Don't add every kind of device to the list.
510 // Core devices are present whether or not we are using plugins, so
511 // they are managed by the same code in iodev/devices.cc whether
512 // plugins are on or off.
514 return; // Do not add core devices to the devices list.
515 case PLUGTYPE_OPTIONAL
:
518 // The plugin system will manage optional and user devices only.
524 /* Empty list, this become the first entry. */
529 /* Non-empty list. Add to end. */
530 device_t
*temp
= devices
;
539 /************************************************************************/
540 /* Plugin system: Check if a plugin is loaded */
541 /************************************************************************/
543 bx_bool
pluginDevicePresent(char *name
)
547 for (device
= devices
; device
; device
= device
->next
)
549 if (strcmp(device
->name
,name
)==0) return true;
556 /************************************************************************/
557 /* Plugin system: Load one plugin */
558 /************************************************************************/
560 int bx_load_plugin(const char *name
, plugintype_t type
)
562 char *namecopy
= new char[1+strlen(name
)];
563 strcpy(namecopy
, name
);
564 plugin_load(namecopy
, "", type
);
568 void bx_unload_plugin(const char *name
)
570 plugin_t
*plugin
, *prev
= NULL
;
572 for (plugin
= plugins
; plugin
; plugin
= plugin
->next
) {
573 if (!strcmp(plugin
->name
, name
)) {
574 plugin
= plugin_unload(plugin
);
587 #endif /* end of #if BX_PLUGINS */
589 /*************************************************************************/
590 /* Plugin system: Execute init function of all registered plugin-devices */
591 /*************************************************************************/
593 void bx_init_plugins()
598 for (device
= devices
; device
; device
= device
->next
)
600 pluginlog
->info("init_mem of '%s' plugin device by virtual method",device
->name
);
601 device
->devmodel
->init_mem(BX_MEM(0));
604 for (device
= devices
; device
; device
= device
->next
)
606 pluginlog
->info("init_dev of '%s' plugin device by virtual method",device
->name
);
607 device
->devmodel
->init();
611 /**************************************************************************/
612 /* Plugin system: Execute reset function of all registered plugin-devices */
613 /**************************************************************************/
615 void bx_reset_plugins(unsigned signal
)
618 for (device
= devices
; device
; device
= device
->next
)
620 pluginlog
->info("reset of '%s' plugin device by virtual method",device
->name
);
621 device
->devmodel
->reset(signal
);
625 /*******************************************************/
626 /* Plugin system: Unload all registered plugin-devices */
627 /*******************************************************/
629 void bx_unload_plugins()
631 device_t
*device
, *next
;
634 while (device
!= NULL
) {
635 if (device
->plugin
!= NULL
) {
637 bx_unload_plugin(device
->name
);
640 delete device
->devmodel
;
649 #if BX_SUPPORT_SAVE_RESTORE
650 /**************************************************************************/
651 /* Plugin system: Register device state of all registered plugin-devices */
652 /**************************************************************************/
654 void bx_plugins_register_state()
657 for (device
= devices
; device
; device
= device
->next
)
659 pluginlog
->info("register state of '%s' plugin device by virtual method",device
->name
);
660 device
->devmodel
->register_state();
664 /***************************************************************************/
665 /* Plugin system: Execute code after restoring state of all plugin devices */
666 /***************************************************************************/
668 void bx_plugins_after_restore_state()
671 for (device
= devices
; device
; device
= device
->next
)
673 device
->devmodel
->after_restore_state();