diff mbox

Support for loading devices as dynamic libraries

Message ID 1345893020-4894-1-git-send-email-dzeromsk@gmail.com
State New
Headers show

Commit Message

Dominik Żeromski Aug. 25, 2012, 11:10 a.m. UTC
Adding support for loading DSO with -device option.

Example Makefile for out of tree modules:
#v+
DEVICENAME=pcnet2

hw-obj-y=pcnet-pci.o
hw-obj-y+=pcnet.o

include rules.mak

.PHONY: all

QEMU_CFLAGS=-I../qemu-kvm -I../qemu-kvm/hw 
QEMU_CFLAGS+=-I../qemu-kvm/fpu -I../qemu-kvm/include
QEMU_CFLAGS+=-I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include

QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=64 -fPIC
LDFLAGS+=-shared

LIBNAME=libqemu_$(DEVICENAME).so

all: $(LIBNAME)

$(LIBNAME): $(hw-obj-y)
	$(call LINK,$^)

clean:
	rm -f *.o
	rm -f *.d
	rm -f $(LIBNAME)

# Include automatically generated dependency files
-include $(patsubst %.o, %.d, $(hw-obj-y))

#v-

Signed-off-by: Dominik Żeromski <dzeromsk@gmail.com>
---
 Makefile.target   |    4 +++-
 hw/qdev-monitor.c |   11 +++++++++++
 2 files changed, 14 insertions(+), 1 deletions(-)

Comments

Stefan Hajnoczi Aug. 25, 2012, 1:53 p.m. UTC | #1
On Sat, Aug 25, 2012 at 12:10 PM, Dominik Żeromski <dzeromsk@gmail.com> wrote:
> Adding support for loading DSO with -device option.
>
> Example Makefile for out of tree modules:

QEMU does not have a stable ABI for devices.  There is a lot of device
model refactoring happening right now for multithreaded MMIO/PIO
dispatch and taking advantage of QEMU Object Model.  A stable ABI
hinders those kinds of improvements.

Send device model patches upstream.  That way you avoid the
maintenance overhead of out-of-tree modules and the QEMU community
doesn't need to provide a stable ABI.

Stefan
Dominik Żeromski Aug. 25, 2012, 5:06 p.m. UTC | #2
2012/8/25 Stefan Hajnoczi <stefanha@gmail.com>
>
> On Sat, Aug 25, 2012 at 12:10 PM, Dominik Żeromski <dzeromsk@gmail.com>
> wrote:
> > Adding support for loading DSO with -device option.
> >
> > Example Makefile for out of tree modules:
>
> QEMU does not have a stable ABI for devices.  There is a lot of device
> model refactoring happening right now for multithreaded MMIO/PIO
> dispatch and taking advantage of QEMU Object Model.  A stable ABI
> hinders those kinds of improvements.
>
> Send device model patches upstream.  That way you avoid the
> maintenance overhead of out-of-tree modules and the QEMU community
> doesn't need to provide a stable ABI.
>

I think that QEMU is a great tool, not only for server virtualization
but also for embedded software and hardware development.

I agree that it would be hard to maintain stable ABI, but this is a
usability feature for device developers, not QEMU developers. I can
imagine use cases where one team works on a hardware emulator and
wants to share it with driver team. Driver team doesn't care about how
QEMU works, how to configure, compile it and then use it. They
probably use qemu-kvm and libvirt provided by some Linux distribution.
The distro qemu-kvm does not change much so it wouldn't be a problem
for emulator team to fix eventual ABI problems. Distributing device as
dynamic library is simply easier for both teams.

-Dominik
Stefan Hajnoczi Aug. 25, 2012, 6:18 p.m. UTC | #3
On Sat, Aug 25, 2012 at 6:06 PM, Dominik Żeromski <dzeromsk@gmail.com> wrote:
> 2012/8/25 Stefan Hajnoczi <stefanha@gmail.com>
>>
>> On Sat, Aug 25, 2012 at 12:10 PM, Dominik Żeromski <dzeromsk@gmail.com>
>> wrote:
>> > Adding support for loading DSO with -device option.
>> >
>> > Example Makefile for out of tree modules:
>>
>> QEMU does not have a stable ABI for devices.  There is a lot of device
>> model refactoring happening right now for multithreaded MMIO/PIO
>> dispatch and taking advantage of QEMU Object Model.  A stable ABI
>> hinders those kinds of improvements.
>>
>> Send device model patches upstream.  That way you avoid the
>> maintenance overhead of out-of-tree modules and the QEMU community
>> doesn't need to provide a stable ABI.
>>
>
> I think that QEMU is a great tool, not only for server virtualization
> but also for embedded software and hardware development.
>
> I agree that it would be hard to maintain stable ABI, but this is a
> usability feature for device developers, not QEMU developers. I can
> imagine use cases where one team works on a hardware emulator and
> wants to share it with driver team. Driver team doesn't care about how
> QEMU works, how to configure, compile it and then use it. They
> probably use qemu-kvm and libvirt provided by some Linux distribution.
> The distro qemu-kvm does not change much so it wouldn't be a problem
> for emulator team to fix eventual ABI problems. Distributing device as
> dynamic library is simply easier for both teams.

The hardware team can provide a qemu-custom-board binary instead of a
bunch of .so files to the driver team.  That way the whole emulator
can be tested and will never have ABI issues.  Device model plugins
don't improve this scenario.

Stefan
Anthony Liguori Aug. 25, 2012, 8:50 p.m. UTC | #4
Dominik Żeromski <dzeromsk@gmail.com> writes:

> Adding support for loading DSO with -device option.

Hi,

A few things:

1) Out of tree modules are boring and there's very little
   support/sympathy for supporting out of tree modules.  That said, if
   you implemented support for in tree modules and the build system
   happened to work with out of tree modules too (as Linux does), you
   would find much more support for that.

2) The GNU module guidelines should be followed.  Namely, we should
   expect modules to declare their licenses and programmatically enforce
   license compatibility.

3) You should use glib's module loading API, not libdl

4) An explicitly insmod command should be used to load modules.  Module
   dependency is very complicated.  It's easier to just load modules in
   a specific order based on a configuration file.

There are very useful reasons to have modules in QEMU.  I really think
Spice support would make sense as a module, for instance.  libspice has
a lot of dependencies and forcing distros to set those dependencies as
dependencies on QEMU really stinks.

So there's pretty good use-cases for in-tree modules.  It's definitely
worth doing.  It's also pretty useful when doing security certifications.

Regards,

Anthony Liguori

>
> Example Makefile for out of tree modules:
> #v+
> DEVICENAME=pcnet2
>
> hw-obj-y=pcnet-pci.o
> hw-obj-y+=pcnet.o
>
> include rules.mak
>
> .PHONY: all
>
> QEMU_CFLAGS=-I../qemu-kvm -I../qemu-kvm/hw 
> QEMU_CFLAGS+=-I../qemu-kvm/fpu -I../qemu-kvm/include
> QEMU_CFLAGS+=-I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
>
> QEMU_CFLAGS+=-DTARGET_PHYS_ADDR_BITS=64 -fPIC
> LDFLAGS+=-shared
>
> LIBNAME=libqemu_$(DEVICENAME).so
>
> all: $(LIBNAME)
>
> $(LIBNAME): $(hw-obj-y)
> 	$(call LINK,$^)
>
> clean:
> 	rm -f *.o
> 	rm -f *.d
> 	rm -f $(LIBNAME)
>
> # Include automatically generated dependency files
> -include $(patsubst %.o, %.d, $(hw-obj-y))
>
> #v-
>
> Signed-off-by: Dominik Żeromski <dzeromsk@gmail.com>
> ---
>  Makefile.target   |    4 +++-
>  hw/qdev-monitor.c |   11 +++++++++++
>  2 files changed, 14 insertions(+), 1 deletions(-)
>
> diff --git a/Makefile.target b/Makefile.target
> index 74f7a4a..7fd9245 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -130,7 +130,9 @@ obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o
>  obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o
>  obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o
>  obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o
> -LIBS+=-lz
> +LIBS+=-lz -ldl
> +
> +LDFLAGS+=-rdynamic
>  
>  QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
>  QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
> diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
> index 7915b45..3b5b0b0 100644
> --- a/hw/qdev-monitor.c
> +++ b/hw/qdev-monitor.c
> @@ -17,6 +17,8 @@
>   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>   */
>  
> +#include <dlfcn.h>
> +
>  #include "qdev.h"
>  #include "monitor.h"
>  #include "qmp-commands.h"
> @@ -402,6 +404,8 @@ DeviceState *qdev_device_add(QemuOpts *opts)
>      const char *driver, *path, *id;
>      DeviceState *qdev;
>      BusState *bus;
> +    void *libhandle;
> +    char libname[NAME_MAX];
>  
>      driver = qemu_opt_get(opts, "driver");
>      if (!driver) {
> @@ -419,7 +423,14 @@ DeviceState *qdev_device_add(QemuOpts *opts)
>              obj = object_class_by_name(driver);
>          }
>      }
> +    if (!obj) {
> +        snprintf(libname, sizeof(libname), "libqemu_%s.so", driver);
>  
> +        libhandle = dlopen(libname, RTLD_NOW);
> +        if (libhandle != NULL) {
> +            obj = object_class_by_name(driver);
> +        }
> +    }
>      if (!obj) {
>          qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
>          return NULL;
> -- 
> 1.7.0.4
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index 74f7a4a..7fd9245 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -130,7 +130,9 @@  obj-$(CONFIG_HAVE_GET_MEMORY_MAPPING) += memory_mapping.o
 obj-$(CONFIG_HAVE_CORE_DUMP) += dump.o
 obj-$(CONFIG_NO_GET_MEMORY_MAPPING) += memory_mapping-stub.o
 obj-$(CONFIG_NO_CORE_DUMP) += dump-stub.o
-LIBS+=-lz
+LIBS+=-lz -ldl
+
+LDFLAGS+=-rdynamic
 
 QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
 QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
index 7915b45..3b5b0b0 100644
--- a/hw/qdev-monitor.c
+++ b/hw/qdev-monitor.c
@@ -17,6 +17,8 @@ 
  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <dlfcn.h>
+
 #include "qdev.h"
 #include "monitor.h"
 #include "qmp-commands.h"
@@ -402,6 +404,8 @@  DeviceState *qdev_device_add(QemuOpts *opts)
     const char *driver, *path, *id;
     DeviceState *qdev;
     BusState *bus;
+    void *libhandle;
+    char libname[NAME_MAX];
 
     driver = qemu_opt_get(opts, "driver");
     if (!driver) {
@@ -419,7 +423,14 @@  DeviceState *qdev_device_add(QemuOpts *opts)
             obj = object_class_by_name(driver);
         }
     }
+    if (!obj) {
+        snprintf(libname, sizeof(libname), "libqemu_%s.so", driver);
 
+        libhandle = dlopen(libname, RTLD_NOW);
+        if (libhandle != NULL) {
+            obj = object_class_by_name(driver);
+        }
+    }
     if (!obj) {
         qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
         return NULL;