qom: add support for qom objects in modules.

build some devices (qxl, virtio-gpu, ccid, usb-redir) as modules.
 build braille chardev as module.
 
 v2: more verbose comment for "build: fix device module builds" patch.
 
 note: qemu doesn't rebuild objects on cflags changes (specifically
       -fPIC being added when code is switched from builtin to module).
       Workaround for resulting build errors: "make clean", rebuild.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCgAGBQJfBHu4AAoJEEy22O7T6HE4uh8P/0clQVfXb8jBsCnLw2dJuvdx
 rJzgZTn5BQElCmZYN43LElyCcD7DO2Exz6JtV554oK/tjH/QkOKAKzPzk+FzhKta
 3zyGvlS79KMHoMoIf6xSIbSv3/jt2iP9TU9HpaHXIBQJTAtExAasEPtr3ewgAhDv
 wd5FC/slM7NNofQgyz5ycAKGddwOYFP/zAnTZPU2noCek2B86OgBX+BN5VIaxn/g
 Reuk4z0QBLWXGmb2j6RbmBKZ61V/qokpz9OjwZ1reRU+tTXOzhu8ROr+GDmNj3D8
 m8mt1t8UUIH35Zo9Lc0+4P6aKCk5gQI4tYukut/8zXqnNdPhQxsnCFiR1U8kZter
 +189dhVXLZ+vp8IMe7piu/a4iU/5Jgz30VUOetrAM0CDjzuI0Bbp1wSjgiLyZ9EC
 CZLxIm2lZCHCr92G4UtmUR0dnacoee96bsAs/Rd9U3DWRLaDwuTNGYPfW1J5fEyn
 nqLscU/8H2H8tQhSjX8nTkxXh29/bA1pzb/auPKkajS+rblACWgYyj8035VyWIiB
 NTJZzvXXAxLNObLZSLteUQLOn5ugjmicH7Q8RJZmcQzudq0PDlJrF8vXJ2R6PZLF
 4ecSgy1b1xA7xvXc4tAdtnlcVvVl/LU5EMWooQP26cKZzJOM0GnUUlBo+K6oEQTf
 0lXrg6LAhH1sevdFzhNd
 =DVlH
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/modules-20200707-pull-request' into staging

qom: add support for qom objects in modules.
build some devices (qxl, virtio-gpu, ccid, usb-redir) as modules.
build braille chardev as module.

v2: more verbose comment for "build: fix device module builds" patch.

note: qemu doesn't rebuild objects on cflags changes (specifically
      -fPIC being added when code is switched from builtin to module).
      Workaround for resulting build errors: "make clean", rebuild.

# gpg: Signature made Tue 07 Jul 2020 14:42:16 BST
# gpg:                using RSA key 4CB6D8EED3E87138
# gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full]
# gpg:                 aka "Gerd Hoffmann <gerd@kraxel.org>" [full]
# gpg:                 aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full]
# Primary key fingerprint: A032 8CFF B93A 17A7 9901  FE7D 4CB6 D8EE D3E8 7138

* remotes/kraxel/tags/modules-20200707-pull-request:
  chardev: enable modules, use for braille
  vga: build virtio-gpu as module
  vga: build virtio-gpu only once
  vga: build qxl as module
  usb: build usb-redir as module
  ccid: build smartcard as module
  build: fix device module builds
  qdev: device module support
  object: qom module support
  module: qom module support

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-07-09 17:02:29 +01:00
commit aff2caf6b3
15 changed files with 155 additions and 24 deletions

View File

@ -59,6 +59,7 @@ common-obj-y += migration/
common-obj-y += audio/
common-obj-m += audio/
common-obj-y += hw/
common-obj-m += hw/
common-obj-y += replay/
@ -70,6 +71,7 @@ common-obj-$(CONFIG_TPM) += tpm.o
common-obj-y += backends/
common-obj-y += chardev/
common-obj-m += chardev/
common-obj-$(CONFIG_SECCOMP) += qemu-seccomp.o
qemu-seccomp.o-cflags := $(SECCOMP_CFLAGS)

View File

@ -179,6 +179,20 @@ endif # CONFIG_SOFTMMU
dummy := $(call unnest-vars,,obj-y)
all-obj-y := $(obj-y)
#
# common-obj-m has some crap here, probably as side effect from
# unnest-vars recursing into target directories to fill obj-y and not
# properly handling the -m case.
#
# Clear common-obj-m as workaround. Fixes suspious dependency errors
# when building devices as modules. A bit hackish, but should be ok
# as long as we do not have any target-specific modules.
#
# The meson-based build system currently in development doesn't need
# unnest-vars and will obsolete this workaround.
#
common-obj-m :=
include $(SRC_PATH)/Makefile.objs
dummy := $(call unnest-vars,.., \
authz-obj-y \

View File

@ -18,8 +18,11 @@ chardev-obj-$(CONFIG_WIN32) += char-win.o
chardev-obj-$(CONFIG_WIN32) += char-win-stdio.o
common-obj-y += msmouse.o wctablet.o testdev.o
common-obj-$(CONFIG_BRLAPI) += baum.o
ifeq ($(CONFIG_BRLAPI),y)
common-obj-m += baum.o
baum.o-cflags := $(SDL_CFLAGS)
baum.o-libs := $(BRLAPI_LIBS)
endif
common-obj-$(CONFIG_SPICE) += spice.o

View File

@ -527,7 +527,7 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
const ChardevClass *cc;
char *typename = g_strdup_printf("chardev-%s", driver);
oc = object_class_by_name(typename);
oc = module_object_class_by_name(typename);
g_free(typename);
if (!object_class_dynamic_cast(oc, TYPE_CHARDEV)) {

View File

@ -43,4 +43,6 @@ devices-dirs-y += smbios/
endif
common-obj-y += $(devices-dirs-y)
common-obj-m += display/
common-obj-m += usb/
obj-y += $(devices-dirs-y)

View File

@ -137,6 +137,9 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
*/
DeviceState *qdev_new(const char *name)
{
if (!object_class_by_name(name)) {
module_load_qom_one(name);
}
return DEVICE(object_new(name));
}
@ -147,10 +150,9 @@ DeviceState *qdev_new(const char *name)
*/
DeviceState *qdev_try_new(const char *name)
{
if (!object_class_by_name(name)) {
if (!module_object_class_by_name(name)) {
return NULL;
}
return DEVICE(object_new(name));
}

View File

@ -44,18 +44,24 @@ common-obj-$(CONFIG_ARTIST) += artist.o
obj-$(CONFIG_VGA) += vga.o
common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
ifeq ($(CONFIG_QXL),y)
common-obj-m += qxl.mo
qxl.mo-objs = qxl.o qxl-logger.o qxl-render.o
endif
ifeq ($(CONFIG_VIRTIO_GPU),y)
common-obj-m += virtio-gpu.mo
virtio-gpu-obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o
virtio-gpu-obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o
virtio-gpu-obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
virtio-gpu-obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o
virtio-gpu-obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
virtio-gpu-obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o
virtio-gpu.mo-objs := $(virtio-gpu-obj-y)
virtio-gpu.mo-cflags := $(VIRGL_CFLAGS)
virtio-gpu.mo-libs := $(VIRGL_LIBS)
endif
obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu-base.o virtio-gpu.o virtio-gpu-3d.o
obj-$(CONFIG_VHOST_USER_GPU) += vhost-user-gpu.o
obj-$(call land,$(CONFIG_VIRTIO_GPU),$(CONFIG_VIRTIO_PCI)) += virtio-gpu-pci.o
obj-$(call land,$(CONFIG_VHOST_USER_GPU),$(CONFIG_VIRTIO_PCI)) += vhost-user-gpu-pci.o
obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
obj-$(CONFIG_VHOST_USER_VGA) += vhost-user-vga.o
virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
virtio-gpu.o-libs += $(VIRGL_LIBS)
virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS)
virtio-gpu-3d.o-libs += $(VIRGL_LIBS)
common-obj-$(CONFIG_DPCD) += dpcd.o
common-obj-$(CONFIG_XLNX_ZYNQMP_ARM) += xlnx_dp.o

View File

@ -29,11 +29,13 @@ common-obj-$(CONFIG_USB_NETWORK) += dev-network.o
ifeq ($(CONFIG_USB_SMARTCARD),y)
common-obj-y += dev-smartcard-reader.o
common-obj-$(CONFIG_SMARTCARD) += smartcard.mo
ifeq ($(CONFIG_SMARTCARD),y)
common-obj-m += smartcard.mo
smartcard.mo-objs := ccid-card-passthru.o ccid-card-emulated.o
smartcard.mo-cflags := $(SMARTCARD_CFLAGS)
smartcard.mo-libs := $(SMARTCARD_LIBS)
endif
endif
ifeq ($(CONFIG_POSIX),y)
common-obj-$(CONFIG_USB_STORAGE_MTP) += dev-mtp.o
@ -41,9 +43,12 @@ endif
# usb redirection
ifeq ($(CONFIG_USB),y)
common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
redirect.o-cflags = $(USB_REDIR_CFLAGS)
redirect.o-libs = $(USB_REDIR_LIBS)
ifeq ($(CONFIG_USB_REDIR),y)
common-obj-m += redirect.mo
redirect.mo-objs = redirect.o quirks.o
redirect.mo-cflags = $(USB_REDIR_CFLAGS)
redirect.mo-libs = $(USB_REDIR_LIBS)
endif
endif
# usb pass-through

View File

@ -70,5 +70,7 @@ void register_dso_module_init(void (*fn)(void), module_init_type type);
void module_call_init(module_init_type type);
bool module_load_one(const char *prefix, const char *lib_name);
void module_load_qom_one(const char *type);
void module_load_qom_all(void);
#endif

View File

@ -994,6 +994,18 @@ bool object_class_is_abstract(ObjectClass *klass);
*/
ObjectClass *object_class_by_name(const char *typename);
/**
* module_object_class_by_name:
* @typename: The QOM typename to obtain the class for.
*
* For objects which might be provided by a module. Behaves like
* object_class_by_name, but additionally tries to load the module
* needed in case the class is not available.
*
* Returns: The class for @typename or %NULL if not found.
*/
ObjectClass *module_object_class_by_name(const char *typename);
void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
const char *implements_type, bool include_abstract,
void *opaque);

View File

@ -149,6 +149,7 @@ static void qdev_print_devinfos(bool show_no_user)
int i;
bool cat_printed;
module_load_qom_all();
list = object_class_get_list_sorted(TYPE_DEVICE, false);
for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) {
@ -217,13 +218,13 @@ static DeviceClass *qdev_get_device_class(const char **driver, Error **errp)
DeviceClass *dc;
const char *original_name = *driver;
oc = object_class_by_name(*driver);
oc = module_object_class_by_name(*driver);
if (!oc) {
const char *typename = find_typename_by_alias(*driver);
if (typename) {
*driver = typename;
oc = object_class_by_name(*driver);
oc = module_object_class_by_name(*driver);
}
}

View File

@ -985,6 +985,20 @@ ObjectClass *object_class_by_name(const char *typename)
return type->class;
}
ObjectClass *module_object_class_by_name(const char *typename)
{
ObjectClass *oc;
oc = object_class_by_name(typename);
#ifdef CONFIG_MODULES
if (!oc) {
module_load_qom_one(typename);
oc = object_class_by_name(typename);
}
#endif
return oc;
}
ObjectClass *object_class_get_parent(ObjectClass *class)
{
TypeImpl *type = type_get_parent(class->type);

View File

@ -116,6 +116,7 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
{
ObjectTypeInfoList *ret = NULL;
module_load_qom_all();
object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
return ret;
@ -130,7 +131,7 @@ ObjectPropertyInfoList *qmp_device_list_properties(const char *typename,
ObjectPropertyIterator iter;
ObjectPropertyInfoList *prop_list = NULL;
klass = object_class_by_name(typename);
klass = module_object_class_by_name(typename);
if (klass == NULL) {
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
"Device '%s' not found", typename);

View File

@ -1772,8 +1772,8 @@ static bool vga_interface_available(VGAInterfaceType t)
assert(t < VGA_TYPE_MAX);
return !ti->class_names[0] ||
object_class_by_name(ti->class_names[0]) ||
object_class_by_name(ti->class_names[1]);
module_object_class_by_name(ti->class_names[0]) ||
module_object_class_by_name(ti->class_names[1]);
}
static const char *

View File

@ -245,3 +245,70 @@ bool module_load_one(const char *prefix, const char *lib_name)
#endif
return success;
}
/*
* Building devices and other qom objects modular is mostly useful in
* case they have dependencies to external shared libraries, so we can
* cut down the core qemu library dependencies. Which is the case for
* only a very few devices & objects.
*
* So with the expectation that this will be rather the exception than
* to rule and the list will not gain that many entries go with a
* simple manually maintained list for now.
*/
static struct {
const char *type;
const char *prefix;
const char *module;
} const qom_modules[] = {
{ "ccid-card-passthru", "hw-", "usb-smartcard" },
{ "ccid-card-emulated", "hw-", "usb-smartcard" },
{ "usb-redir", "hw-", "usb-redirect" },
{ "qxl-vga", "hw-", "display-qxl" },
{ "qxl", "hw-", "display-qxl" },
{ "virtio-gpu-device", "hw-", "display-virtio-gpu" },
{ "virtio-gpu-pci", "hw-", "display-virtio-gpu" },
{ "virtio-vga", "hw-", "display-virtio-gpu" },
{ "vhost-user-gpu-device", "hw-", "display-virtio-gpu" },
{ "vhost-user-gpu-pci", "hw-", "display-virtio-gpu" },
{ "vhost-user-vga", "hw-", "display-virtio-gpu" },
{ "chardev-braille", "chardev-", "baum" },
};
static bool module_loaded_qom_all;
void module_load_qom_one(const char *type)
{
int i;
if (module_loaded_qom_all) {
return;
}
for (i = 0; i < ARRAY_SIZE(qom_modules); i++) {
if (strcmp(qom_modules[i].type, type) == 0) {
module_load_one(qom_modules[i].prefix,
qom_modules[i].module);
return;
}
}
}
void module_load_qom_all(void)
{
int i;
if (module_loaded_qom_all) {
return;
}
for (i = 0; i < ARRAY_SIZE(qom_modules); i++) {
if (i > 0 && (strcmp(qom_modules[i - 1].module,
qom_modules[i].module) == 0 &&
strcmp(qom_modules[i - 1].prefix,
qom_modules[i].prefix) == 0)) {
/* one module implementing multiple types -> load only once */
continue;
}
module_load_one(qom_modules[i].prefix, qom_modules[i].module);
}
module_loaded_qom_all = true;
}