1 /////////////////////////////////////////////////////////////////////////
2 // $Id: plugin.cc,v 1.25 2008/02/15 22:05:38 sshwarts 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 /************************************************************************/
250 void plugin_init_all (void)
254 pluginlog
->info("Initializing plugins");
256 for (plugin
= plugins
; plugin
; plugin
= plugin
->next
)
258 char *arg_ptr
= plugin
->args
;
260 /* process the command line */
262 while (plugin
->argc
< MAX_ARGC
)
264 while (*arg_ptr
&& isspace (*arg_ptr
))
267 if (!*arg_ptr
) break;
268 plugin
->argv
[plugin
->argc
++] = arg_ptr
;
270 while (*arg_ptr
&& !isspace (*arg_ptr
))
273 if (!*arg_ptr
) break;
277 /* initialize the plugin */
278 if (plugin
->plugin_init (plugin
, plugin
->type
, plugin
->argc
, plugin
->argv
))
280 pluginlog
->panic("Plugin initialization failed for %s", plugin
->name
);
284 plugin
->initialized
= 1;
288 void plugin_init_one(plugin_t
*plugin
)
290 char *arg_ptr
= plugin
->args
;
292 /* process the command line */
294 while (plugin
->argc
< MAX_ARGC
)
296 while (*arg_ptr
&& isspace (*arg_ptr
))
299 if (!*arg_ptr
) break;
300 plugin
->argv
[plugin
->argc
++] = arg_ptr
;
302 while (*arg_ptr
&& !isspace (*arg_ptr
))
305 if (!*arg_ptr
) break;
309 /* initialize the plugin */
310 if (plugin
->plugin_init (plugin
, plugin
->type
, plugin
->argc
, plugin
->argv
))
312 pluginlog
->info("Plugin initialization failed for %s", plugin
->name
);
316 plugin
->initialized
= 1;
320 plugin_t
*plugin_unload(plugin_t
*plugin
)
324 if (plugin
->initialized
)
325 plugin
->plugin_fini();
327 lt_dlclose(plugin
->handle
);
328 delete [] plugin
->name
;
331 plugin
= plugin
->next
;
337 void plugin_fini_all (void)
341 for (plugin
= plugins
; plugin
; plugin
= plugin_unload(plugin
));
344 void plugin_load(char *name
, char *args
, plugintype_t type
)
348 plugin
= (plugin_t
*)malloc (sizeof(plugin_t
));
351 BX_PANIC(("malloc plugin_t failed"));
357 plugin
->initialized
= 0;
359 char plugin_filename
[BX_PATHNAME_LEN
], buf
[BX_PATHNAME_LEN
];
360 sprintf(buf
, PLUGIN_FILENAME_FORMAT
, name
);
361 sprintf(plugin_filename
, "%s%s", PLUGIN_PATH
, buf
);
363 // Set context so that any devices that the plugin registers will
364 // be able to see which plugin created them. The registration will
365 // be called from either dlopen (global constructors) or plugin_init.
366 BX_ASSERT(current_plugin_context
== NULL
);
367 current_plugin_context
= plugin
;
368 plugin
->handle
= lt_dlopen (plugin_filename
);
369 BX_INFO(("lt_dlhandle is %p", plugin
->handle
));
372 current_plugin_context
= NULL
;
373 BX_PANIC(("dlopen failed for module '%s': %s", name
, lt_dlerror ()));
378 sprintf(buf
, PLUGIN_INIT_FMT_STRING
, name
);
379 plugin
->plugin_init
=
380 (int (*)(struct _plugin_t
*, enum plugintype_t
, int, char *[])) /* monster typecast */
381 lt_dlsym (plugin
->handle
, buf
);
382 if (plugin
->plugin_init
== NULL
) {
383 pluginlog
->panic("could not find plugin_init: %s", lt_dlerror ());
387 sprintf(buf
, PLUGIN_FINI_FMT_STRING
, name
);
388 plugin
->plugin_fini
= (void (*)(void)) lt_dlsym (plugin
->handle
, buf
);
389 if (plugin
->plugin_init
== NULL
) {
390 pluginlog
->panic("could not find plugin_fini: %s", lt_dlerror ());
393 pluginlog
->info("loaded plugin %s",plugin_filename
);
395 /* Insert plugin at the _end_ of the plugin linked list. */
400 /* Empty list, this become the first entry. */
405 /* Non-empty list. Add to end. */
406 plugin_t
*temp
= plugins
;
414 plugin_init_one(plugin
);
416 // check that context didn't change. This should only happen if we
417 // need a reentrant plugin_load.
418 BX_ASSERT(current_plugin_context
== plugin
);
419 current_plugin_context
= NULL
;
422 void plugin_abort(void)
424 pluginlog
->panic("plugin load aborted");
427 #endif /* end of #if BX_PLUGINS */
429 /************************************************************************/
430 /* Plugin system: initialisation of plugins entry points */
431 /************************************************************************/
436 pluginRegisterIRQ
= builtinRegisterIRQ
;
437 pluginUnregisterIRQ
= builtinUnregisterIRQ
;
439 pluginSetHRQHackCallback
= builtinSetHRQHackCallback
;
440 pluginSetHRQ
= builtinSetHRQ
;
442 pluginRegisterIOReadHandler
= builtinRegisterIOReadHandler
;
443 pluginRegisterIOWriteHandler
= builtinRegisterIOWriteHandler
;
445 pluginUnregisterIOReadHandler
= builtinUnregisterIOReadHandler
;
446 pluginUnregisterIOWriteHandler
= builtinUnregisterIOWriteHandler
;
448 pluginRegisterIOReadHandlerRange
= builtinRegisterIOReadHandlerRange
;
449 pluginRegisterIOWriteHandlerRange
= builtinRegisterIOWriteHandlerRange
;
451 pluginUnregisterIOReadHandlerRange
= builtinUnregisterIOReadHandlerRange
;
452 pluginUnregisterIOWriteHandlerRange
= builtinUnregisterIOWriteHandlerRange
;
454 pluginRegisterDefaultIOReadHandler
= builtinRegisterDefaultIOReadHandler
;
455 pluginRegisterDefaultIOWriteHandler
= builtinRegisterDefaultIOWriteHandler
;
457 pluginRegisterTimer
= builtinRegisterTimer
;
458 pluginActivateTimer
= builtinActivateTimer
;
461 pluginlog
= new logfunctions();
462 pluginlog
->put("PLGIN");
463 pluginlog
->settype(PLUGINLOG
);
464 int status
= lt_dlinit ();
466 BX_ERROR (("initialization error in ltdl library (for loading plugins)"));
467 BX_PANIC (("error message was: %s", lt_dlerror ()));
473 /************************************************************************/
474 /* Plugin system: Device registration */
475 /************************************************************************/
477 void pluginRegisterDeviceDevmodel(plugin_t
*plugin
, plugintype_t type
, bx_devmodel_c
*devmodel
, const char *name
)
481 device
= (device_t
*)malloc (sizeof (device_t
));
484 pluginlog
->panic("can't allocate device_t");
488 BX_ASSERT(devmodel
!= NULL
);
489 device
->devmodel
= devmodel
;
490 device
->plugin
= plugin
; // this can be NULL
493 // Don't add every kind of device to the list.
496 // Core devices are present whether or not we are using plugins, so
497 // they are managed by the same code in iodev/devices.cc whether
498 // plugins are on or off.
500 return; // Do not add core devices to the devices list.
501 case PLUGTYPE_OPTIONAL
:
504 // The plugin system will manage optional and user devices only.
509 /* Empty list, this become the first entry. */
513 /* Non-empty list. Add to end. */
514 device_t
*temp
= devices
;
523 /************************************************************************/
524 /* Plugin system: Check if a plugin is loaded */
525 /************************************************************************/
527 bx_bool
pluginDevicePresent(char *name
)
531 for (device
= devices
; device
; device
= device
->next
)
533 if (strcmp(device
->name
,name
)==0) return true;
540 /************************************************************************/
541 /* Plugin system: Load one plugin */
542 /************************************************************************/
544 int bx_load_plugin(const char *name
, plugintype_t type
)
546 char *namecopy
= new char[1+strlen(name
)];
547 strcpy(namecopy
, name
);
548 plugin_load(namecopy
, "", type
);
552 void bx_unload_plugin(const char *name
)
554 plugin_t
*plugin
, *prev
= NULL
;
556 for (plugin
= plugins
; plugin
; plugin
= plugin
->next
) {
557 if (!strcmp(plugin
->name
, name
)) {
558 plugin
= plugin_unload(plugin
);
571 #endif /* end of #if BX_PLUGINS */
573 /*************************************************************************/
574 /* Plugin system: Execute init function of all registered plugin-devices */
575 /*************************************************************************/
577 void bx_init_plugins()
582 for (device
= devices
; device
; device
= device
->next
)
584 pluginlog
->info("init_mem of '%s' plugin device by virtual method",device
->name
);
585 device
->devmodel
->init_mem(BX_MEM(0));
588 for (device
= devices
; device
; device
= device
->next
)
590 pluginlog
->info("init_dev of '%s' plugin device by virtual method",device
->name
);
591 device
->devmodel
->init();
595 /**************************************************************************/
596 /* Plugin system: Execute reset function of all registered plugin-devices */
597 /**************************************************************************/
599 void bx_reset_plugins(unsigned signal
)
602 for (device
= devices
; device
; device
= device
->next
)
604 pluginlog
->info("reset of '%s' plugin device by virtual method",device
->name
);
605 device
->devmodel
->reset(signal
);
609 /*******************************************************/
610 /* Plugin system: Unload all registered plugin-devices */
611 /*******************************************************/
613 void bx_unload_plugins()
615 device_t
*device
, *next
;
618 while (device
!= NULL
) {
619 if (device
->plugin
!= NULL
) {
621 bx_unload_plugin(device
->name
);
624 delete device
->devmodel
;
633 /**************************************************************************/
634 /* Plugin system: Register device state of all registered plugin-devices */
635 /**************************************************************************/
637 void bx_plugins_register_state()
640 for (device
= devices
; device
; device
= device
->next
)
642 pluginlog
->info("register state of '%s' plugin device by virtual method",device
->name
);
643 device
->devmodel
->register_state();
647 /***************************************************************************/
648 /* Plugin system: Execute code after restoring state of all plugin devices */
649 /***************************************************************************/
651 void bx_plugins_after_restore_state()
654 for (device
= devices
; device
; device
= device
->next
)
656 device
->devmodel
->after_restore_state();