docs/devel: add plugins.rst design document
This is mostly extracted from Emilio's more verbose commit comments with some additional verbiage from me. Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
136094d0b2
commit
027e3332b8
@ -22,3 +22,4 @@ Contents:
|
|||||||
decodetree
|
decodetree
|
||||||
secure-coding-practices
|
secure-coding-practices
|
||||||
tcg
|
tcg
|
||||||
|
plugins
|
||||||
|
112
docs/devel/plugins.rst
Normal file
112
docs/devel/plugins.rst
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
..
|
||||||
|
Copyright (C) 2017, Emilio G. Cota <cota@braap.org>
|
||||||
|
Copyright (c) 2019, Linaro Limited
|
||||||
|
Written by Emilio Cota and Alex Bennée
|
||||||
|
|
||||||
|
================
|
||||||
|
QEMU TCG Plugins
|
||||||
|
================
|
||||||
|
|
||||||
|
QEMU TCG plugins provide a way for users to run experiments taking
|
||||||
|
advantage of the total system control emulation can have over a guest.
|
||||||
|
It provides a mechanism for plugins to subscribe to events during
|
||||||
|
translation and execution and optionally callback into the plugin
|
||||||
|
during these events. TCG plugins are unable to change the system state
|
||||||
|
only monitor it passively. However they can do this down to an
|
||||||
|
individual instruction granularity including potentially subscribing
|
||||||
|
to all load and store operations.
|
||||||
|
|
||||||
|
API Stability
|
||||||
|
=============
|
||||||
|
|
||||||
|
This is a new feature for QEMU and it does allow people to develop
|
||||||
|
out-of-tree plugins that can be dynamically linked into a running QEMU
|
||||||
|
process. However the project reserves the right to change or break the
|
||||||
|
API should it need to do so. The best way to avoid this is to submit
|
||||||
|
your plugin upstream so they can be updated if/when the API changes.
|
||||||
|
|
||||||
|
|
||||||
|
Exposure of QEMU internals
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
The plugin architecture actively avoids leaking implementation details
|
||||||
|
about how QEMU's translation works to the plugins. While there are
|
||||||
|
conceptions such as translation time and translation blocks the
|
||||||
|
details are opaque to plugins. The plugin is able to query select
|
||||||
|
details of instructions and system configuration only through the
|
||||||
|
exported *qemu_plugin* functions. The types used to describe
|
||||||
|
instructions and events are opaque to the plugins themselves.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
The QEMU binary needs to be compiled for plugin support:
|
||||||
|
|
||||||
|
::
|
||||||
|
configure --enable-plugins
|
||||||
|
|
||||||
|
Once built a program can be run with multiple plugins loaded each with
|
||||||
|
their own arguments:
|
||||||
|
|
||||||
|
::
|
||||||
|
$QEMU $OTHER_QEMU_ARGS \
|
||||||
|
-plugin tests/plugin/libhowvec.so,arg=inline,arg=hint \
|
||||||
|
-plugin tests/plugin/libhotblocks.so
|
||||||
|
|
||||||
|
Arguments are plugin specific and can be used to modify their
|
||||||
|
behaviour. In this case the howvec plugin is being asked to use inline
|
||||||
|
ops to count and break down the hint instructions by type.
|
||||||
|
|
||||||
|
Plugin Life cycle
|
||||||
|
=================
|
||||||
|
|
||||||
|
First the plugin is loaded and the public qemu_plugin_install function
|
||||||
|
is called. The plugin will then register callbacks for various plugin
|
||||||
|
events. Generally plugins will register a handler for the *atexit*
|
||||||
|
if they want to dump a summary of collected information once the
|
||||||
|
program/system has finished running.
|
||||||
|
|
||||||
|
When a registered event occurs the plugin callback is invoked. The
|
||||||
|
callbacks may provide additional information. In the case of a
|
||||||
|
translation event the plugin has an option to enumerate the
|
||||||
|
instructions in a block of instructions and optionally register
|
||||||
|
callbacks to some or all instructions when they are executed.
|
||||||
|
|
||||||
|
There is also a facility to add an inline event where code to
|
||||||
|
increment a counter can be directly inlined with the translation.
|
||||||
|
Currently only a simple increment is supported. This is not atomic so
|
||||||
|
can miss counts. If you want absolute precision you should use a
|
||||||
|
callback which can then ensure atomicity itself.
|
||||||
|
|
||||||
|
Finally when QEMU exits all the registered *atexit* callbacks are
|
||||||
|
invoked.
|
||||||
|
|
||||||
|
Internals
|
||||||
|
=========
|
||||||
|
|
||||||
|
Locking
|
||||||
|
-------
|
||||||
|
|
||||||
|
We have to ensure we cannot deadlock, particularly under MTTCG. For
|
||||||
|
this we acquire a lock when called from plugin code. We also keep the
|
||||||
|
list of callbacks under RCU so that we do not have to hold the lock
|
||||||
|
when calling the callbacks. This is also for performance, since some
|
||||||
|
callbacks (e.g. memory access callbacks) might be called very
|
||||||
|
frequently.
|
||||||
|
|
||||||
|
* A consequence of this is that we keep our own list of CPUs, so that
|
||||||
|
we do not have to worry about locking order wrt cpu_list_lock.
|
||||||
|
* Use a recursive lock, since we can get registration calls from
|
||||||
|
callbacks.
|
||||||
|
|
||||||
|
As a result registering/unregistering callbacks is "slow", since it
|
||||||
|
takes a lock. But this is very infrequent; we want performance when
|
||||||
|
calling (or not calling) callbacks, not when registering them. Using
|
||||||
|
RCU is great for this.
|
||||||
|
|
||||||
|
We support the uninstallation of a plugin at any time (e.g. from
|
||||||
|
plugin callbacks). This allows plugins to remove themselves if they no
|
||||||
|
longer want to instrument the code. This operation is asynchronous
|
||||||
|
which means callbacks may still occur after the uninstall operation is
|
||||||
|
requested. The plugin isn't completely uninstalled until the safe work
|
||||||
|
has executed while all vCPUs are quiescent.
|
Loading…
Reference in New Issue
Block a user