Jeroen Janssen wrote:
>
> It might be usefull if (at least) the plugin API would be "documented".
>
> (I can understand plex86 internals might be difficult to document, or
> they might change in the near future, but a small description of each
> function in the plugin API wouldn't hurt :))
Yeah, there should be documentation, but
nobody has been bothered to make it yet ;).
The sourcecode is your friend.
But anyhow, here's a short description:
***
(1) Functions in plugins
***
(1.1) Every plugin needs to have at least two functions,
plugin_init() and plugin_fini(). If these don't exist,
the plugin will fail to load.
***
int
plugin_init (plugin_t *plugin, int argc, char *argv[]);
is called when the plugin is first loaded. It will only
be called once in a plugin's lifetime. Here, the plugin
can perform initialisations, etc.
Arguments:
plugin_t *plugin is the plugin handle; many plugin
functions take this as a parameter,
so it is best to save this in a
global variable or something.
int argc,
char *argv[] The plugin commandline, in standard
C format, as given in plex86.conf
Return value: 0 for success
!= 0 for failed initialisation
***
void
plugin_fini (void);
is called just before the plugin is unloaded. The plugin
can use this function to perform deinitialisation.
***
(1.2) When a plugin allocates an event, it needs to give
the address of the event handler callback, which will be
called by the main program when an event comes in. All
handlers are of the same type:
typedef int (*handler_t)
(event_t event, int data, int op_size, int count, void *loc);
event_t event specifies the type of event that came in
(this way, different events can be handled by the same
handler. Event types can be found in plugin.h, right
now we have: EVT_INPORT, EVT_OUTPORT, EVT_INT.
int data is the primary event data (the port that I/O
is done to/from, or the interrupt vector that was called.)
int op_size is the operand size of the event. It is unused
for interrupts, and for port I/O it shows whether this
is a one-byte, two-byte or four-byte I/O operation.
int count and void *loc are unused for interrupts;
for I/O, void *loc is a pointer to the data that was
written or requested; count gives the amount of op_size'd
data items written/requested.
Right now count=1 (always), in the future count could be >1
for rep ins/outs instructions.
The idea is that when the guest does an outport, the plugin
can find the data that was out'd to the port in void *loc.
When the guest does an inport, the plugin handler gets
called and is supposed to fill in the value(s) to be returned
to the guest in the void *loc array.
Return value:
for I/O ports: doesn't matter, just return 0
for interrupts: return 0 if interrupt was handled completely
return != 0 if interrupt is to be reflected
back into the guest.
***
(2) Functions called by plugins
***
(2.1) Resource functions
***
int
plugin_alloc_inp(plugin_t *plugin, handler_t handler, int base, int range);
int
plugin_alloc_outp(plugin_t *plugin, handler_t handler, int base, int range);
These functions are used to allocate I/O ports for input
from the plugin to the guest (_inp) and for output from
the guest to the plugin (_outp). Parameters:
plugin_t *plugin: plugin handle of plugin to allocate
I/O port to
handler_t handler: I/O event handler to send events for
this I/O port to
int base: The first I/O port to allocate
int range: The amount of I/O ports to allocate,
starting at base
Return 0 on success, otherwise != 0
***
void
plugin_free_inp(plugin_t *plugin, int base, int range);
void
plugin_free_outp(plugin_t *plugin, int base, int range);
Same as the functions above, but these free the ports in
stead of allocating them.
***
int
plugin_alloc_intr (plugin_t *plugin, handler_t handler, int vec);
Allocates and interrupt for handling by the plugin.
Parameters:
plugin_t *plugin: handle of plugin to allocate interrupt to
handler_t *handler: interrupt handler in plugin
int vec: interrupt vector to allocate
Returns 0 on success, otherwise != 0
***
void
plugin_free_intr (plugin_t *plugin, int vec);
Same as above, but this function frees the interrupt
in stead of allocating it.
***
void
plugin_abort (void);
This function aborts the VM. Use it for clean
shutdown (never do exit() !)
***
(2.2) Pending support
Some plugins handle unix signals; however, not all
plugin actions are safe to perform from a signal
handler. For instance, X functions should not be
called from a signal handler; for those functions,
the plugin *could* launch a separate thread. However,
the plugin functions like the ones described here are
not reentrant, so they may neither be called from a
signal handler nor from a separate thread.
Both problems are handled using the only reentrant
plugin function, plugin_enqueue(). From the signal
handler, the plugin may call
void
plugin_enqueue (void (*func) (void));
The signal can now return; and the function func()
will be called back from the main loop of the user
program, where reentrancy is not a problem. The
callback func() should then complete handling the
signal.
***
(2.3) Functions used by one plugin only
Some functions should (can) only be called by one plugin
(FCFS), so most plugin authors should not bother with
them. These are:
void
plugin_announce_iac_handler (iac_handler_t handler);
void
plugin_set_intr (int intr);
These functions are used by the plugin emulating the
PIC to handle virtualised hardware interrupts.
void
plugin_register_elapsed(void (*funct)(Bit64u));
This function is used to handle VM timing. Perhaps
this should be made available to all plugins later
on; for now, better not mess with it.
***
(2.4) VM functions
Most of the functions in user.c aren't all that relevant
to plugin writers, but these can be / are important:
***
void
vm_get_context (guest_context_t *context);
void
vm_set_context (guest_context_t *context);
These functions get or set the virtual processor
context. The guest context structure looks like
this:
typedef struct
{
Bit32u gs;
Bit32u fs;
Bit32u ds;
Bit32u es;
Bit32u edi;
Bit32u esi;
Bit32u ebp;
Bit32u dummy_esp;
Bit32u ebx;
Bit32u edx;
Bit32u ecx;
Bit32u eax;
Bit32u vector;
Bit32u error;
Bit32u eip;
Bit32u cs;
Bit32u eflags;
Bit32u esp;
Bit32u ss;
} guest_context_t;
This is pretty self-documenting.
***
int
vm_read_physical (Bit32u address, unsigned length, void *data);
int
vm_write_physical (Bit32u address, unsigned length, void *data);
These functions are used to read / write guest physical memory
to or from a buffer. Usage: address is always the
address of the virtualised physical memory, data is the
address of the buffer to read from / write to. length
is the length of data to read/write
Return value: 0 on success, != 0 on error (usu out of bounds)
***
That's more or less all you need to know!
If you have more questions, that's what this
list is for.
-- Ramon