[PATCH 01/11] MAINTAINERS: Add Connor Kuehl as reviewer for AMD SEV

2021-06-10 Thread Philippe Mathieu-Daudé
From: Connor Kuehl 

It may not be appropriate for me to take over as a maintainer at this time,
but I would consider myself familiar with AMD SEV and what this code is
meant to be doing as part of a VMM for launching SEV-protected guests.

To that end, I would be happy to volunteer as a reviewer for SEV-related
changes so that I am CC'd on them and can help share the review burden with
whoever does maintain this code.

Signed-off-by: Connor Kuehl 
Message-Id: <20210608192537.103584-1-cku...@redhat.com>
[PMD: Cover more files]
Signed-off-by: Philippe Mathieu-Daudé 
---
 MAINTAINERS | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 56888121ec8..a93f4ba1861 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2938,6 +2938,13 @@ F: hw/core/clock-vmstate.c
 F: hw/core/qdev-clock.c
 F: docs/devel/clocks.rst
 
+AMD Secure Encrypted Virtualization (SEV)
+R: Connor Kuehl 
+F: docs/amd-memory-encryption.txt
+F: accel/kvm/sev-stub.c
+F: target/i386/sev*
+F: include/sysemu/sev.h
+
 Usermode Emulation
 --
 Overall usermode emulation
-- 
2.31.1




[PATCH 00/11] target/i386/sev: Housekeeping helping using SEV-disabled binaries

2021-06-10 Thread Philippe Mathieu-Daudé
Hi,

I wasted some time trying to figure out how OVMF was supposed to
behave until realizing the binary I was using was built without SEV
support... Then wrote this series to help other developers to not
hit the same problem.
Some SEV patches I was following have been queued on Eduardo's
'x86-next' tree, so I used his tree as base, and included David and
Connor patches to reduce merge conflicts.

Based-on: https://gitlab.com/ehabkost/qemu/-/commits/x86-next/

Connor Kuehl (1):
  MAINTAINERS: Add Connor Kuehl as reviewer for AMD SEV

Dr. David Alan Gilbert (1):
  target/i386/sev: sev_get_attestation_report use g_autofree

Philippe Mathieu-Daudé (9):
  qapi/misc-target: Group SEV QAPI definitions
  target/i386/monitor: Return QMP error when SEV is disabled in build
  target/i386/cpu: Add missing 'qapi/error.h' header
  target/i386/sev_i386.h: Remove unused headers
  target/i386/sev: Remove sev_get_me_mask()
  target/i386/sev: Mark unreachable code with g_assert_not_reached()
  target/i386/sev: Restrict SEV to system emulation
  target/i386/monitor: Move SEV specific commands to sev.c
  monitor: Restrict 'info sev' to x86 targets

 qapi/misc-target.json |  75 +++---
 include/monitor/hmp-target.h  |   1 +
 include/monitor/hmp.h |   1 -
 target/i386/sev_i386.h|   5 --
 target/i386/cpu.c |   1 +
 target/i386/monitor.c |  91 --
 target/i386/sev-stub.c|  49 +-
 target/i386/sev-sysemu-stub.c |  69 
 target/i386/sev.c | 117 +-
 MAINTAINERS   |   7 ++
 target/i386/meson.build   |   4 +-
 11 files changed, 219 insertions(+), 201 deletions(-)
 create mode 100644 target/i386/sev-sysemu-stub.c

-- 
2.31.1





Re: [RFC PATCH 0/5] ebpf: Added ebpf helper for libvirtd.

2021-06-10 Thread Jason Wang



在 2021/6/9 下午6:04, Andrew Melnychenko 写道:

Libvirt usually launches qemu with strict permissions.
To enable eBPF RSS steering, qemu-ebpf-rss-helper was added.



A silly question:

Kernel had the following permission checks in bpf syscall:

   if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
    return -EPERM;
...

    err = security_bpf(cmd, , size);
    if (err < 0)
    return err;

So if I understand the code correctly, bpf syscall can only be done if:

1) unprivileged_bpf is enabled or
2) has the capability  and pass the LSM checks

So I think the series is for unprivileged_bpf disabled. If I'm not 
wrong, I guess the policy is to grant CAP_BPF but do fine grain checks 
via LSM.


If this is correct, need to describe it in the commit log.




Added property "ebpf_rss_fds" for "virtio-net" that allows to
initialize eBPF RSS context with passed program & maps fds.

Added qemu-ebpf-rss-helper - simple helper that loads eBPF
context and passes fds through unix socket.
Libvirt should call the helper and pass fds to qemu through
"ebpf_rss_fds" property.

Added explicit target OS check for libbpf dependency in meson.
eBPF RSS works only with Linux TAP, so there is no reason to
build eBPF loader/helper for non-Linux.

Overall, libvirt process should not be aware of the "interface"
of eBPF RSS, it will not be aware of eBPF maps/program "type" and
their quantity.



I'm not sure this is the best. We have several examples that let libvirt 
to involve. Examples:


1) create TAP device (and the TUN_SETIFF)

2) open vhost devices



  That's why qemu and the helper should be from
the same build and be "synchronized". Technically each qemu may
have its own helper. That's why "query-helper-paths" qmp command
was added. Qemu should return the path to the helper that suits
and libvirt should use "that" helper for "that" emulator.

qmp sample:
C: { "execute": "query-helper-paths" }
S: { "return": [
  {
"name": "qemu-ebpf-rss-helper",
"path": "/usr/local/libexec/qemu-ebpf-rss-helper"
  }
 ]
}



I think we need an example on the detail steps for how libvirt is 
expected to use this.


Thanks




Andrew Melnychenko (5):
   ebpf: Added eBPF initialization by fds.
   virtio-net: Added property to load eBPF RSS with fds.
   ebpf_rss_helper: Added helper for eBPF RSS.
   qmp: Added qemu-ebpf-rss-path command.
   meson: libbpf dependency now exclusively for Linux.

  ebpf/ebpf_rss-stub.c   |   6 ++
  ebpf/ebpf_rss.c|  31 +++-
  ebpf/ebpf_rss.h|   5 ++
  ebpf/qemu-ebpf-rss-helper.c| 130 +
  hw/net/virtio-net.c|  77 ++-
  include/hw/virtio/virtio-net.h |   1 +
  meson.build|  37 ++
  monitor/qmp-cmds.c |  78 
  qapi/misc.json |  29 
  9 files changed, 374 insertions(+), 20 deletions(-)
  create mode 100644 ebpf/qemu-ebpf-rss-helper.c






Re: [PATCH v4 00/13] [RfC] fix tracing for modules

2021-06-10 Thread Gerd Hoffmann
On Wed, Jun 09, 2021 at 04:14:12PM +0100, Stefan Hajnoczi wrote:
> On Tue, Jun 01, 2021 at 03:24:01PM +0200, Gerd Hoffmann wrote:
> > First version that actually works.  Only qxl covered for this RfC,
> > other modules will follow once the basics are hashed out.
> > 
> > v4:
> >  - rebase to latest master.
> >  - fix systemtap tracing.
> >  - also cover virtio-gpu modules.
> >  - pick up some review tags.
> >  - misc minor tweaks.
> > 
> > v3:
> >  - handle initialization of modular tracepoints.
> > 
> > TODO:
> > Enabling modular tracepoints via -trace cmd line doesn't work yet.
> > Guess we need to store the list somewhere for later re-processing.
> > Error handling is tricky, specifically the "tracepoint doesn't exist"
> > error.  Suggestions / ideas are welcome.
> 
> Excellent! I think we discussed these TODOs in the past. Can we merge
> this series in close to its current form or does it degrade the tracing
> experience (e.g. does the -trace command-line no longer work for
> trace-events files that were split off into modules)?

Main focus for v4 was to make stap work.
The cmd line issue is still there.

Patches 1-5 can be cherry-picked without breaking something.

take care,
  Gerd




Re: [PATCH v2 18/18] [fixup] module_load_modinfo

2021-06-10 Thread Gerd Hoffmann
On Thu, Jun 10, 2021 at 07:57:55AM +0200, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann 

Oops.  That should have been squashed into patch #13.

take care,
  Gerd




Re: [PATCH v6 3/4] Jobs based on custom runners: docs and gitlab-runner setup playbook

2021-06-10 Thread Thomas Huth

On 08/06/2021 05.14, Cleber Rosa wrote:

To have the jobs dispatched to custom runners, gitlab-runner must
be installed, active as a service and properly configured.  The
variables file and playbook introduced here should help with those
steps.

The playbook introduced here covers the Linux distributions and
has been primarily tested on OS/machines that the QEMU project
has available to act as runners, namely:

  * Ubuntu 20.04 on aarch64
  * Ubuntu 18.04 on s390x

But, it should work on all other Linux distributions.  Earlier
versions were tested on FreeBSD too, so chances of success are
high.

Signed-off-by: Cleber Rosa 
---
  docs/devel/ci.rst  | 57 
  scripts/ci/setup/.gitignore|  1 +
  scripts/ci/setup/gitlab-runner.yml | 61 ++
  scripts/ci/setup/vars.yml.template | 12 ++
  4 files changed, 131 insertions(+)
  create mode 100644 scripts/ci/setup/.gitignore
  create mode 100644 scripts/ci/setup/gitlab-runner.yml
  create mode 100644 scripts/ci/setup/vars.yml.template

[...]

diff --git a/scripts/ci/setup/.gitignore b/scripts/ci/setup/.gitignore
new file mode 100644
index 00..f112d05dd0
--- /dev/null
+++ b/scripts/ci/setup/.gitignore
@@ -0,0 +1 @@
+vars.yml
\ No newline at end of file


Add a newline, please.


diff --git a/scripts/ci/setup/gitlab-runner.yml 
b/scripts/ci/setup/gitlab-runner.yml
new file mode 100644
index 00..98dab92bb5
--- /dev/null
+++ b/scripts/ci/setup/gitlab-runner.yml
@@ -0,0 +1,61 @@
+---
+- name: Installation of gitlab-runner
+  hosts: all
+  vars_files:
+- vars.yml
+  tasks:
+- debug:
+msg: 'Checking for a valid GitLab registration token'
+  failed_when: "gitlab_runner_registration_token == 
'PLEASE_PROVIDE_A_VALID_TOKEN'"


Could you please add a comment at the top of the file or name it differently 
so that it is clear from a quick glance that this is an ansible playbook? 
Poeple might later wonder otherwise...


 Thomas




[Bug 1921948] Re: MTE tags not checked properly for unaligned accesses at EL1

2021-06-10 Thread Thomas Huth
Thanks for opening the new ticket. I'm closing this one here on
Launchpad now so that we don't accidentally migrate it later
automatically.

** Changed in: qemu
   Status: Confirmed => Fix Released

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1921948

Title:
  MTE tags not checked properly for unaligned accesses at EL1

Status in QEMU:
  Fix Released

Bug description:
  For kernel memory accesses that span across two memory granules,
  QEMU's MTE implementation only checks the tag of the first granule but
  not of the second one.

  To reproduce this, build the Linux kernel with CONFIG_KASAN_HW_TAGS
  enabled, apply the patch below, and boot the kernel:

  diff --git a/sound/last.c b/sound/last.c
  index f0bb98780e70..04745cb30b74 100644
  --- a/sound/last.c
  +++ b/sound/last.c
  @@ -5,12 +5,18 @@
*/
   
   #include 
  +#include 
   #include 
   
   static int __init alsa_sound_last_init(void)
   {
  struct snd_card *card;
  int idx, ok = 0;
  +
  +   char *ptr = kmalloc(128, GFP_KERNEL);
  +   pr_err("KASAN report should follow:\n");
  +   *(volatile unsigned long *)(ptr + 124);
  +   kfree(ptr);
  
  printk(KERN_INFO "ALSA device list:\n");
  for (idx = 0; idx < SNDRV_CARDS; idx++) {

  KASAN tags the 128 allocated bytes with the same tag as the returned
  pointer. The memory granule that follows the 128 allocated bytes has a
  different tag (with 1/15 probability).

  Expected result: a tag fault is detected and a KASAN report is printed when 
accessing bytes [124, 130).
  Observed result: no tag fault is detected and no KASAN report is printed.

  Here are the flags that I use to run QEMU if they matter:

  qemu-system-aarch64 -s -machine virt,mte=on -cpu max -m 2G -smp 2 -net
  user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22 -net nic
  -nographic -kernel ./Image -append "console=ttyAMA0 root=/dev/vda
  earlyprintk=serial" -drive file=./fs.img,format=raw,if=virtio -no-
  shutdown -no-reboot

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1921948/+subscriptions



Re: [PATCH v6 4/4] Jobs based on custom runners: add job definitions for QEMU's machines

2021-06-10 Thread Thomas Huth

On 08/06/2021 05.14, Cleber Rosa wrote:

The QEMU project has two machines (aarch64 and s390x) that can be used
for jobs that do build and run tests.  This introduces those jobs,
which are a mapping of custom scripts used for the same purpose.

Signed-off-by: Cleber Rosa 
---
  .gitlab-ci.d/custom-runners.yml | 208 
  1 file changed, 208 insertions(+)

diff --git a/.gitlab-ci.d/custom-runners.yml b/.gitlab-ci.d/custom-runners.yml
index a07b27384c..061d3cdfed 100644
--- a/.gitlab-ci.d/custom-runners.yml
+++ b/.gitlab-ci.d/custom-runners.yml
@@ -12,3 +12,211 @@
  # guarantees a fresh repository on each job run.
  variables:
GIT_STRATEGY: clone
+
+# All ubuntu-18.04 jobs should run successfully in an environment
+# setup by the scripts/ci/setup/build-environment.yml task
+# "Install basic packages to build QEMU on Ubuntu 18.04/20.04"
+ubuntu-18.04-s390x-all-linux-static:
+ allow_failure: true
+ needs: []
+ stage: build
+ tags:
+ - ubuntu_18.04
+ - s390x
+ rules:
+ - if: '$CI_COMMIT_BRANCH =~ /^staging/'


I don't think this will work very well... sub-maintainers might want to push 
to a "staging" branch in their forked repositories, and without the s390x 
runner, the pipeline gets stuck now:


 https://gitlab.com/thuth/qemu/-/pipelines/317812558

We had the same issue in the kvm-unit-test CI, and we solved it there by 
rather making it depend on an environment variable that has to be set if the 
runner is available:


 only:
   variables:
- $S390X_RUNNER_AVAILABLE

I think that's also nicer in case someone brings their own s390x runner and 
want to use the CI tests on other branches than staging.


Could you please change your patch accordingly?

 Thanks,
  Thomas




Re: [RFC PATCH 2/4] target/ppc: divided mmu_helper.c in 2 files

2021-06-10 Thread David Gibson
On Mon, Jun 07, 2021 at 03:35:06PM -0300, Lucas Mateus Martins Araujo e Castro 
wrote:
> 
> On 06/06/2021 23:31, David Gibson wrote:
> > On Wed, Jun 02, 2021 at 04:26:02PM -0300, Lucas Mateus Castro (alqotel) 
> > wrote:
> > > Moved functions in mmu_helper.c that should be compiled in build to
> > > mmu_common.c, moved declaration of functions that both files use to
> > > cpu.h and moved struct declarations and inline functions needed by
> > > both to target/ppc/internal.h. Updated meson.build to compile the
> > > new file.
> > > 
> > > Signed-off-by: Lucas Mateus Castro (alqotel) 
> > > 
> > > ---
> > > Had to turn a few functions non static as it was used by both
> > > mmu_common.c and mmu_helper.c. Added the declaration of mmu_ctx_t to
> > > cpu.h so functions there can reference it and added the definition to
> > > internal.h so functions in both mmu_* files can access it.
> > > And maybe the tlb functions should be declared in internal.h instead of
> > > cpu.h.
> > > ---
> > >   target/ppc/cpu.h|   35 +
> > >   target/ppc/internal.h   |   26 +
> > >   target/ppc/meson.build  |6 +-
> > >   target/ppc/mmu_common.c | 1606 ++
> > >   target/ppc/mmu_helper.c | 1814 +++
> > >   5 files changed, 1774 insertions(+), 1713 deletions(-)
> > >   create mode 100644 target/ppc/mmu_common.c
> > > 
> > > diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
> > > index b0934d9be4..cfc35ef83e 100644
> > > --- a/target/ppc/cpu.h
> > > +++ b/target/ppc/cpu.h
> > > @@ -1329,6 +1329,41 @@ void store_booke_tsr(CPUPPCState *env, 
> > > target_ulong val);
> > >   void ppc_tlb_invalidate_all(CPUPPCState *env);
> > >   void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr);
> > >   void cpu_ppc_set_vhyp(PowerPCCPU *cpu, PPCVirtualHypervisor *vhyp);
> > > +
> > > +typedef struct mmu_ctx_t mmu_ctx_t;
> > > +int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
> > > +hwaddr *raddrp,
> > > +target_ulong address, uint32_t pid, int ext,
> > > +int i);
> > > +int get_physical_address_wtlb(CPUPPCState *env, mmu_ctx_t *ctx,
> > > + target_ulong eaddr,
> > > + MMUAccessType access_type, int type,
> > > + int mmu_idx);
> > > +hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
> > > +ppcmas_tlb_t *tlb);
> > > +int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
> > > +hwaddr *raddrp, target_ulong address,
> > > +uint32_t pid);
> > > +int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
> > > +target_ulong eaddr, MMUAccessType 
> > > access_type,
> > > +int type);
> > > +static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
> > > +int way, int is_code)
> > > +{
> > > +int nr;
> > > +
> > > +/* Select TLB num in a way from address */
> > > +nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
> > > +/* Select TLB way */
> > > +nr += env->tlb_per_way * way;
> > > +/* 6xx have separate TLBs for instructions and data */
> > > +if (is_code && env->id_tlbs == 1) {
> > > +nr += env->nb_tlb;
> > > +}
> > > +
> > > +return nr;
> > > +}
> > This is a rather complex and model specific function to have inline in
> > a header.
> What is the best way to deal with this function? It's used by both
> mmu_helper.c and mmu_common.c so I put it there as a way to keep it being an
> inline function, so it would be best to put it in target/ppc/internal.h or
> maybe just turn it into a not inline function?

There's no good reason for this to be inline.  Just put it in
mmu_common.c and export.

-- 
David Gibson| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson


signature.asc
Description: PGP signature


[PATCH v2 18/18] [fixup] module_load_modinfo

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 util/module.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/util/module.c b/util/module.c
index 564b8e3da760..4f98cc74ae37 100644
--- a/util/module.c
+++ b/util/module.c
@@ -158,7 +158,7 @@ static void module_load_modinfo(void)
 {
 char *file, *json;
 FILE *fp;
-int i, size;
+int i, size, ret;
 Visitor *v;
 Error *errp = NULL;
 
@@ -185,8 +185,8 @@ static void module_load_modinfo(void)
 size = ftell(fp);
 fseek(fp, 0, SEEK_SET);
 json = g_malloc0(size + 1);
-fread(json, size, 1, fp);
-json[size] = 0;
+ret = fread(json, 1, size, fp);
+json[ret] = 0;
 fclose(fp);
 
 v = qobject_input_visitor_new_str(json, NULL, );
-- 
2.31.1




[PATCH v2 16/18] modules: use modinfo for qemu opts load

2021-06-10 Thread Gerd Hoffmann
Use module database to figure which module adds given QemuOpts group.

Signed-off-by: Gerd Hoffmann 
---
 softmmu/vl.c| 17 -
 stubs/module-opts.c |  4 
 util/module.c   | 19 +++
 3 files changed, 19 insertions(+), 21 deletions(-)

diff --git a/softmmu/vl.c b/softmmu/vl.c
index 326c1e908008..ba26a042b284 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -2675,23 +2675,6 @@ void qmp_x_exit_preconfig(Error **errp)
 }
 }
 
-#ifdef CONFIG_MODULES
-void qemu_load_module_for_opts(const char *group)
-{
-static bool spice_tried;
-if (g_str_equal(group, "spice") && !spice_tried) {
-ui_module_load_one("spice-core");
-spice_tried = true;
-}
-
-static bool iscsi_tried;
-if (g_str_equal(group, "iscsi") && !iscsi_tried) {
-block_module_load_one("iscsi");
-iscsi_tried = true;
-}
-}
-#endif
-
 void qemu_init(int argc, char **argv, char **envp)
 {
 QemuOpts *opts;
diff --git a/stubs/module-opts.c b/stubs/module-opts.c
index a7d0e4ad6ead..5412429ea869 100644
--- a/stubs/module-opts.c
+++ b/stubs/module-opts.c
@@ -1,6 +1,2 @@
 #include "qemu/osdep.h"
 #include "qemu/config-file.h"
-
-void qemu_load_module_for_opts(const char *group)
-{
-}
diff --git a/util/module.c b/util/module.c
index 46bec1cfbec7..6e4199169c41 100644
--- a/util/module.c
+++ b/util/module.c
@@ -21,6 +21,7 @@
 #include "qemu/module.h"
 #include "qemu/cutils.h"
 #include "qemu/error-report.h"
+#include "qemu/config-file.h"
 #ifdef CONFIG_MODULE_UPGRADES
 #include "qemu-version.h"
 #endif
@@ -381,8 +382,26 @@ void module_load_qom_all(void)
 module_loaded_qom_all = true;
 }
 
+void qemu_load_module_for_opts(const char *group)
+{
+ModuleInfoList *modlist;
+
+module_load_path_init();
+module_load_modinfo();
+
+for (modlist = modinfo->list; modlist != NULL; modlist = modlist->next) {
+if (!modlist->value->has_opts) {
+continue;
+}
+if (strcmp(modlist->value->opts, group) == 0) {
+module_load_one("", modlist->value->name, false);
+}
+}
+}
+
 #else
 
+void qemu_load_module_for_opts(const char *group) {}
 void module_load_qom_one(const char *type) {}
 void module_load_qom_all(void) {}
 
-- 
2.31.1




[PATCH v2 12/18] modules: add module_load_path_init helper

2021-06-10 Thread Gerd Hoffmann
Factor out module search path initialization to the new
module_load_path_init() helper.  Also store the search path in
global variables and keep it so we have to do it only once.

Signed-off-by: Gerd Hoffmann 
---
 util/module.c | 58 ++-
 1 file changed, 34 insertions(+), 24 deletions(-)

diff --git a/util/module.c b/util/module.c
index eee8ff2de136..3a2d6dde9734 100644
--- a/util/module.c
+++ b/util/module.c
@@ -110,6 +110,36 @@ void module_call_init(module_init_type type)
 }
 
 #ifdef CONFIG_MODULES
+
+static char *module_dirs[5];
+static int module_ndirs;
+
+static void module_load_path_init(void)
+{
+const char *search_dir;
+
+if (module_ndirs) {
+return;
+}
+
+search_dir = getenv("QEMU_MODULE_DIR");
+if (search_dir != NULL) {
+module_dirs[module_ndirs++] = g_strdup_printf("%s", search_dir);
+}
+module_dirs[module_ndirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
+module_dirs[module_ndirs++] = g_strdup(qemu_get_exec_dir());
+
+#ifdef CONFIG_MODULE_UPGRADES
+version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
+ G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
+ '_');
+module_dirs[module_ndirs++] = g_strdup_printf("/var/run/qemu/%s", 
version_dir);
+#endif
+
+assert(module_ndirs <= ARRAY_SIZE(module_dirs));
+
+}
+
 static int module_load_file(const char *fname, bool mayfail, bool 
export_symbols)
 {
 GModule *g_module;
@@ -204,10 +234,8 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 #ifdef CONFIG_MODULE_UPGRADES
 char *version_dir;
 #endif
-const char *search_dir;
-char *dirs[5];
 char *module_name;
-int i = 0, n_dirs = 0;
+int i = 0;
 int ret, dep;
 bool export_symbols = false;
 static GHashTable *loaded_modules;
@@ -240,25 +268,11 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 }
 g_hash_table_add(loaded_modules, module_name);
 
-search_dir = getenv("QEMU_MODULE_DIR");
-if (search_dir != NULL) {
-dirs[n_dirs++] = g_strdup_printf("%s", search_dir);
-}
-dirs[n_dirs++] = get_relocated_path(CONFIG_QEMU_MODDIR);
-dirs[n_dirs++] = g_strdup(qemu_get_exec_dir());
+module_load_path_init();
 
-#ifdef CONFIG_MODULE_UPGRADES
-version_dir = g_strcanon(g_strdup(QEMU_PKGVERSION),
- G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "+-.~",
- '_');
-dirs[n_dirs++] = g_strdup_printf("/var/run/qemu/%s", version_dir);
-#endif
-
-assert(n_dirs <= ARRAY_SIZE(dirs));
-
-for (i = 0; i < n_dirs; i++) {
+for (i = 0; i < module_ndirs; i++) {
 fname = g_strdup_printf("%s/%s%s",
-dirs[i], module_name, CONFIG_HOST_DSOSUF);
+module_dirs[i], module_name, CONFIG_HOST_DSOSUF);
 ret = module_load_file(fname, mayfail, export_symbols);
 g_free(fname);
 fname = NULL;
@@ -274,10 +288,6 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 g_free(module_name);
 }
 
-for (i = 0; i < n_dirs; i++) {
-g_free(dirs[i]);
-}
-
 #endif
 return success;
 }
-- 
2.31.1




[PATCH v2 13/18] modules: load modinfo.json

2021-06-10 Thread Gerd Hoffmann
Load and parse the module info database.

Signed-off-by: Gerd Hoffmann 
---
 util/module.c | 54 +++
 util/trace-events |  3 +++
 2 files changed, 57 insertions(+)

diff --git a/util/module.c b/util/module.c
index 3a2d6dde9734..b0ea8c57d438 100644
--- a/util/module.c
+++ b/util/module.c
@@ -20,9 +20,16 @@
 #include "qemu/queue.h"
 #include "qemu/module.h"
 #include "qemu/cutils.h"
+#include "qemu/error-report.h"
 #ifdef CONFIG_MODULE_UPGRADES
 #include "qemu-version.h"
 #endif
+#include "trace.h"
+
+#include "qapi/error.h"
+#include "qapi/qapi-types-modules.h"
+#include "qapi/qapi-visit-modules.h"
+#include "qapi/qobject-input-visitor.h"
 
 typedef struct ModuleEntry
 {
@@ -111,6 +118,7 @@ void module_call_init(module_init_type type)
 
 #ifdef CONFIG_MODULES
 
+static Modules *modinfo;
 static char *module_dirs[5];
 static int module_ndirs;
 
@@ -137,7 +145,52 @@ static void module_load_path_init(void)
 #endif
 
 assert(module_ndirs <= ARRAY_SIZE(module_dirs));
+}
 
+static void module_load_modinfo(void)
+{
+char *file, *json;
+FILE *fp;
+int i, size;
+Visitor *v;
+Error *errp = NULL;
+
+if (modinfo) {
+return;
+}
+
+for (i = 0; i < module_ndirs; i++) {
+file = g_strdup_printf("%s/modinfo.json", module_dirs[i]);
+fp = fopen(file, "r");
+if (fp != NULL) {
+break;
+}
+g_free(file);
+}
+if (NULL == fp) {
+warn_report("No modinfo.json file found.");
+return;
+} else {
+trace_module_load_modinfo(file);
+}
+
+fseek(fp, 0, SEEK_END);
+size = ftell(fp);
+fseek(fp, 0, SEEK_SET);
+json = g_malloc0(size + 1);
+fread(json, size, 1, fp);
+json[size] = 0;
+fclose(fp);
+
+v = qobject_input_visitor_new_str(json, NULL, );
+if (errp) {
+error_reportf_err(errp, "parse error (%s)", file);
+g_free(file);
+return;
+}
+visit_type_Modules(v, NULL, , );
+visit_free(v);
+g_free(file);
 }
 
 static int module_load_file(const char *fname, bool mayfail, bool 
export_symbols)
@@ -269,6 +322,7 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 g_hash_table_add(loaded_modules, module_name);
 
 module_load_path_init();
+module_load_modinfo();
 
 for (i = 0; i < module_ndirs; i++) {
 fname = g_strdup_printf("%s/%s%s",
diff --git a/util/trace-events b/util/trace-events
index 806cac14a762..8b2afcbd109a 100644
--- a/util/trace-events
+++ b/util/trace-events
@@ -100,3 +100,6 @@ uffd_create_fd_api_failed(int err) "errno: %i"
 uffd_create_fd_api_noioctl(uint64_t ioctl_req, uint64_t ioctl_supp) 
"ioctl_req: 0x%" PRIx64 "ioctl_supp: 0x%" PRIx64
 uffd_register_memory_failed(void *addr, uint64_t length, uint64_t mode, int 
err) "addr: %p length: %" PRIu64 " mode: 0x%" PRIx64 " errno: %i"
 uffd_unregister_memory_failed(void *addr, uint64_t length, int err) "addr: %p 
length: %" PRIu64 " errno: %i"
+
+# module.c
+module_load_modinfo(const char *filename) "modinfo %s"
-- 
2.31.1




[PATCH v2 15/18] modules: use modinfo for qom load

2021-06-10 Thread Gerd Hoffmann
Use module database to figure which module implements a given QOM type.
Drop hard-coded object list.

Signed-off-by: Gerd Hoffmann 
---
 util/module.c | 83 +++
 1 file changed, 30 insertions(+), 53 deletions(-)

diff --git a/util/module.c b/util/module.c
index fd5fc059e14a..46bec1cfbec7 100644
--- a/util/module.c
+++ b/util/module.c
@@ -333,80 +333,57 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 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
- * the rule and the list will not gain that many entries, go with a
- * simple manually maintained list for now.
- *
- * The list must be sorted by module (module_load_qom_all() needs this).
- */
-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-gl-device",  "hw-", "display-virtio-gpu-gl" },
-{ "vhost-user-gpu","hw-", "display-virtio-gpu"},
-{ "virtio-gpu-pci-base",   "hw-", "display-virtio-gpu-pci" },
-{ "virtio-gpu-pci","hw-", "display-virtio-gpu-pci" },
-{ "virtio-gpu-gl-pci", "hw-", "display-virtio-gpu-pci-gl" },
-{ "vhost-user-gpu-pci","hw-", "display-virtio-gpu-pci" },
-{ "virtio-gpu-ccw","hw-", "s390x-virtio-gpu-ccw"   },
-{ "virtio-vga-base",   "hw-", "display-virtio-vga"},
-{ "virtio-vga","hw-", "display-virtio-vga"},
-{ "virtio-vga-gl", "hw-", "display-virtio-vga-gl" },
-{ "vhost-user-vga","hw-", "display-virtio-vga"},
-{ "chardev-braille",   "chardev-", "baum" },
-{ "chardev-spicevmc",  "chardev-", "spice"},
-{ "chardev-spiceport", "chardev-", "spice"},
-};
+#ifdef CONFIG_MODULES
 
 static bool module_loaded_qom_all;
 
 void module_load_qom_one(const char *type)
 {
-int i;
+ModuleInfoList *modlist;
+strList *sl;
 
 if (!type) {
 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,
-false);
-return;
+
+module_load_path_init();
+module_load_modinfo();
+
+for (modlist = modinfo->list; modlist != NULL; modlist = modlist->next) {
+if (!modlist->value->has_objs) {
+continue;
+}
+for (sl = modlist->value->objs; sl != NULL; sl = sl->next) {
+if (strcmp(type, sl->value) == 0) {
+module_load_one("", modlist->value->name, false);
+}
 }
 }
 }
 
 void module_load_qom_all(void)
 {
-int i;
+ModuleInfoList *modlist;
 
 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 */
+
+module_load_path_init();
+module_load_modinfo();
+
+for (modlist = modinfo->list; modlist != NULL; modlist = modlist->next) {
+if (!modlist->value->has_objs) {
 continue;
 }
-module_load_one(qom_modules[i].prefix, qom_modules[i].module, true);
+module_load_one("", modlist->value->name, false);
 }
 module_loaded_qom_all = true;
 }
+
+#else
+
+void module_load_qom_one(const char *type) {}
+void module_load_qom_all(void) {}
+
+#endif
-- 
2.31.1




[PATCH v2 08/18] modules: add ccid module annotations

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 hw/usb/ccid-card-emulated.c | 1 +
 hw/usb/ccid-card-passthru.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c
index 5c76bed77aa0..6c8c0355e099 100644
--- a/hw/usb/ccid-card-emulated.c
+++ b/hw/usb/ccid-card-emulated.c
@@ -612,6 +612,7 @@ static const TypeInfo emulated_card_info = {
 .instance_size = sizeof(EmulatedState),
 .class_init= emulated_class_initfn,
 };
+module_obj(TYPE_EMULATED_CCID);
 
 static void ccid_card_emulated_register_types(void)
 {
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index 7212d0d7fb5e..fa3040fb7154 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -414,6 +414,7 @@ static const TypeInfo passthru_card_info = {
 .instance_size = sizeof(PassthruState),
 .class_init= passthru_class_initfn,
 };
+module_obj(TYPE_CCID_PASSTHRU);
 
 static void ccid_card_passthru_register_types(void)
 {
-- 
2.31.1




[PATCH v2 14/18] modules: use modinfo for dependencies

2021-06-10 Thread Gerd Hoffmann
Use module database for module dependencies.
Drop hard-coded dependency list.

Signed-off-by: Gerd Hoffmann 
---
 util/module.c | 55 ---
 1 file changed, 21 insertions(+), 34 deletions(-)

diff --git a/util/module.c b/util/module.c
index b0ea8c57d438..fd5fc059e14a 100644
--- a/util/module.c
+++ b/util/module.c
@@ -254,28 +254,6 @@ static int module_load_file(const char *fname, bool 
mayfail, bool export_symbols
 out:
 return ret;
 }
-
-static const struct {
-const char *name;
-const char *dep;
-} module_deps[] = {
-{ "audio-spice","ui-spice-core" },
-{ "chardev-spice",  "ui-spice-core" },
-{ "hw-display-qxl", "ui-spice-core" },
-{ "ui-spice-app",   "ui-spice-core" },
-{ "ui-spice-app",   "chardev-spice" },
-
-{ "hw-display-virtio-gpu-gl", "hw-display-virtio-gpu" },
-{ "hw-display-virtio-gpu-pci-gl", "hw-display-virtio-gpu-pci" },
-{ "hw-display-virtio-vga-gl", "hw-display-virtio-vga" },
-
-#ifdef CONFIG_OPENGL
-{ "ui-egl-headless", "ui-opengl"},
-{ "ui-gtk",  "ui-opengl"},
-{ "ui-sdl",  "ui-opengl"},
-{ "ui-spice-core",   "ui-opengl"},
-#endif
-};
 #endif
 
 bool module_load_one(const char *prefix, const char *lib_name, bool mayfail)
@@ -289,9 +267,11 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 #endif
 char *module_name;
 int i = 0;
-int ret, dep;
+int ret;
 bool export_symbols = false;
 static GHashTable *loaded_modules;
+ModuleInfoList *modlist;
+strList *sl;
 
 if (!g_module_supported()) {
 fprintf(stderr, "Module is not supported by system.\n");
@@ -304,17 +284,6 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 
 module_name = g_strdup_printf("%s%s", prefix, lib_name);
 
-for (dep = 0; dep < ARRAY_SIZE(module_deps); dep++) {
-if (strcmp(module_name, module_deps[dep].name) == 0) {
-/* we depend on another module */
-module_load_one("", module_deps[dep].dep, false);
-}
-if (strcmp(module_name, module_deps[dep].dep) == 0) {
-/* another module depends on us */
-export_symbols = true;
-}
-}
-
 if (g_hash_table_contains(loaded_modules, module_name)) {
 g_free(module_name);
 return true;
@@ -324,6 +293,24 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 module_load_path_init();
 module_load_modinfo();
 
+for (modlist = modinfo->list; modlist != NULL; modlist = modlist->next) {
+if (modlist->value->has_deps) {
+if (strcmp(modlist->value->name, module_name) == 0) {
+/* we depend on other module(s) */
+for (sl = modlist->value->deps; sl != NULL; sl = sl->next) {
+module_load_one("", sl->value, false);
+}
+} else {
+for (sl = modlist->value->deps; sl != NULL; sl = sl->next) {
+if (strcmp(module_name, sl->value) == 0) {
+/* another module depends on us */
+export_symbols = true;
+}
+}
+}
+}
+}
+
 for (i = 0; i < module_ndirs; i++) {
 fname = g_strdup_printf("%s/%s%s",
 module_dirs[i], module_name, CONFIG_HOST_DSOSUF);
-- 
2.31.1




[PATCH v2 10/18] modules: add s390x module annotations

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 hw/s390x/virtio-ccw-gpu.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/hw/s390x/virtio-ccw-gpu.c b/hw/s390x/virtio-ccw-gpu.c
index 75a9e4bb3908..5868a2a07093 100644
--- a/hw/s390x/virtio-ccw-gpu.c
+++ b/hw/s390x/virtio-ccw-gpu.c
@@ -59,6 +59,7 @@ static const TypeInfo virtio_ccw_gpu = {
 .instance_init = virtio_ccw_gpu_instance_init,
 .class_init= virtio_ccw_gpu_class_init,
 };
+module_obj(TYPE_VIRTIO_GPU_CCW);
 
 static void virtio_ccw_gpu_register(void)
 {
@@ -68,3 +69,5 @@ static void virtio_ccw_gpu_register(void)
 }
 
 type_init(virtio_ccw_gpu_register)
+
+module_arch("s390x");
-- 
2.31.1




[PATCH v2 04/18] modules: add virtio-gpu module annotations

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 hw/display/vhost-user-gpu-pci.c | 1 +
 hw/display/vhost-user-gpu.c | 1 +
 hw/display/vhost-user-vga.c | 1 +
 hw/display/virtio-gpu-base.c| 1 +
 hw/display/virtio-gpu-gl.c  | 3 +++
 hw/display/virtio-gpu-pci-gl.c  | 3 +++
 hw/display/virtio-gpu-pci.c | 2 ++
 hw/display/virtio-gpu.c | 1 +
 hw/display/virtio-vga-gl.c  | 3 +++
 hw/display/virtio-vga.c | 2 ++
 10 files changed, 18 insertions(+)

diff --git a/hw/display/vhost-user-gpu-pci.c b/hw/display/vhost-user-gpu-pci.c
index a02b23ecaf11..daefcf710159 100644
--- a/hw/display/vhost-user-gpu-pci.c
+++ b/hw/display/vhost-user-gpu-pci.c
@@ -43,6 +43,7 @@ static const VirtioPCIDeviceTypeInfo vhost_user_gpu_pci_info 
= {
 .instance_size = sizeof(VhostUserGPUPCI),
 .instance_init = vhost_user_gpu_pci_initfn,
 };
+module_obj(TYPE_VHOST_USER_GPU_PCI);
 
 static void vhost_user_gpu_pci_register_types(void)
 {
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index 6cdaa1c73b9b..32ef0061f924 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -596,6 +596,7 @@ static const TypeInfo vhost_user_gpu_info = {
 .instance_finalize = vhost_user_gpu_instance_finalize,
 .class_init = vhost_user_gpu_class_init,
 };
+module_obj(TYPE_VHOST_USER_GPU);
 
 static void vhost_user_gpu_register_types(void)
 {
diff --git a/hw/display/vhost-user-vga.c b/hw/display/vhost-user-vga.c
index a34a99856d73..072c9c65bc75 100644
--- a/hw/display/vhost-user-vga.c
+++ b/hw/display/vhost-user-vga.c
@@ -44,6 +44,7 @@ static const VirtioPCIDeviceTypeInfo vhost_user_vga_info = {
 .instance_size = sizeof(VhostUserVGA),
 .instance_init = vhost_user_vga_inst_initfn,
 };
+module_obj(TYPE_VHOST_USER_VGA);
 
 static void vhost_user_vga_register_types(void)
 {
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index dd294276cb38..c8da4806e0bb 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -256,6 +256,7 @@ static const TypeInfo virtio_gpu_base_info = {
 .class_init = virtio_gpu_base_class_init,
 .abstract = true
 };
+module_obj(TYPE_VIRTIO_GPU_BASE);
 
 static void
 virtio_register_types(void)
diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c
index d971b480806a..7ab93bf8c829 100644
--- a/hw/display/virtio-gpu-gl.c
+++ b/hw/display/virtio-gpu-gl.c
@@ -154,6 +154,7 @@ static const TypeInfo virtio_gpu_gl_info = {
 .instance_size = sizeof(VirtIOGPUGL),
 .class_init = virtio_gpu_gl_class_init,
 };
+module_obj(TYPE_VIRTIO_GPU_GL);
 
 static void virtio_register_types(void)
 {
@@ -161,3 +162,5 @@ static void virtio_register_types(void)
 }
 
 type_init(virtio_register_types)
+
+module_dep("hw-display-virtio-gpu");
diff --git a/hw/display/virtio-gpu-pci-gl.c b/hw/display/virtio-gpu-pci-gl.c
index 902dda345275..99b14a07185e 100644
--- a/hw/display/virtio-gpu-pci-gl.c
+++ b/hw/display/virtio-gpu-pci-gl.c
@@ -46,6 +46,7 @@ static const VirtioPCIDeviceTypeInfo virtio_gpu_gl_pci_info = 
{
 .instance_size = sizeof(VirtIOGPUGLPCI),
 .instance_init = virtio_gpu_gl_initfn,
 };
+module_obj(TYPE_VIRTIO_GPU_GL_PCI);
 
 static void virtio_gpu_gl_pci_register_types(void)
 {
@@ -53,3 +54,5 @@ static void virtio_gpu_gl_pci_register_types(void)
 }
 
 type_init(virtio_gpu_gl_pci_register_types)
+
+module_dep("hw-display-virtio-gpu-pci");
diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
index d742a30aecf7..e36eee0c409b 100644
--- a/hw/display/virtio-gpu-pci.c
+++ b/hw/display/virtio-gpu-pci.c
@@ -64,6 +64,7 @@ static const TypeInfo virtio_gpu_pci_base_info = {
 .class_init = virtio_gpu_pci_base_class_init,
 .abstract = true
 };
+module_obj(TYPE_VIRTIO_GPU_PCI_BASE);
 
 #define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
 typedef struct VirtIOGPUPCI VirtIOGPUPCI;
@@ -90,6 +91,7 @@ static const VirtioPCIDeviceTypeInfo virtio_gpu_pci_info = {
 .instance_size = sizeof(VirtIOGPUPCI),
 .instance_init = virtio_gpu_initfn,
 };
+module_obj(TYPE_VIRTIO_GPU_PCI);
 
 static void virtio_gpu_pci_register_types(void)
 {
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 4d549377cbc1..68fd607c2711 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1419,6 +1419,7 @@ static const TypeInfo virtio_gpu_info = {
 .class_size = sizeof(VirtIOGPUClass),
 .class_init = virtio_gpu_class_init,
 };
+module_obj(TYPE_VIRTIO_GPU);
 
 static void virtio_register_types(void)
 {
diff --git a/hw/display/virtio-vga-gl.c b/hw/display/virtio-vga-gl.c
index c971340ebb1a..f22549097c5e 100644
--- a/hw/display/virtio-vga-gl.c
+++ b/hw/display/virtio-vga-gl.c
@@ -36,6 +36,7 @@ static VirtioPCIDeviceTypeInfo virtio_vga_gl_info = {
 .instance_size = sizeof(VirtIOVGAGL),
 .instance_init = virtio_vga_gl_inst_initfn,
 };
+module_obj(TYPE_VIRTIO_VGA_GL);
 
 static void virtio_vga_register_types(void)
 {
@@ -45,3 +46,5 @@ static void virtio_vga_register_types(void)

[PATCH v2 09/18] modules: add ui module annotations

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 ui/egl-headless.c | 4 
 ui/gtk.c  | 4 
 ui/sdl2.c | 4 
 ui/spice-app.c| 3 +++
 ui/spice-core.c   | 5 +
 5 files changed, 20 insertions(+)

diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index da377a74af69..75404e0e8700 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -213,3 +213,7 @@ static void register_egl(void)
 }
 
 type_init(register_egl);
+
+#ifdef CONFIG_OPENGL
+module_dep("ui-opengl");
+#endif
diff --git a/ui/gtk.c b/ui/gtk.c
index 98046f577b9d..376b4d528daa 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -2333,3 +2333,7 @@ static void register_gtk(void)
 }
 
 type_init(register_gtk);
+
+#ifdef CONFIG_OPENGL
+module_dep("ui-opengl");
+#endif
diff --git a/ui/sdl2.c b/ui/sdl2.c
index a203cb0239e1..36d9010cb6c1 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -918,3 +918,7 @@ static void register_sdl1(void)
 }
 
 type_init(register_sdl1);
+
+#ifdef CONFIG_OPENGL
+module_dep("ui-opengl");
+#endif
diff --git a/ui/spice-app.c b/ui/spice-app.c
index 4325ac2d9c54..641f4a9d53e3 100644
--- a/ui/spice-app.c
+++ b/ui/spice-app.c
@@ -221,3 +221,6 @@ static void register_spice_app(void)
 }
 
 type_init(register_spice_app);
+
+module_dep("ui-spice-core");
+module_dep("chardev-spice");
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 272d19b0c152..86d43783acac 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -1037,3 +1037,8 @@ static void spice_register_config(void)
 qemu_add_opts(_spice_opts);
 }
 opts_init(spice_register_config);
+module_opts("spice");
+
+#ifdef CONFIG_OPENGL
+module_dep("ui-opengl");
+#endif
-- 
2.31.1




[PATCH v2 11/18] modules: add block module annotations

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 block/iscsi-opts.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/block/iscsi-opts.c b/block/iscsi-opts.c
index afaf8837d6c1..4f2da405e645 100644
--- a/block/iscsi-opts.c
+++ b/block/iscsi-opts.c
@@ -68,3 +68,4 @@ static void iscsi_block_opts_init(void)
 }
 
 block_init(iscsi_block_opts_init);
+module_opts("iscsi");
-- 
2.31.1




[PATCH v2 03/18] modules: add qemu-modinfo utility

2021-06-10 Thread Gerd Hoffmann
Scan .modinfo sections of qemu modules,
write module metadata to modinfo.json.

Signed-off-by: Gerd Hoffmann 
---
 qemu-modinfo.c | 270 +
 meson.build|  11 ++
 2 files changed, 281 insertions(+)
 create mode 100644 qemu-modinfo.c

diff --git a/qemu-modinfo.c b/qemu-modinfo.c
new file mode 100644
index ..611dbdb00683
--- /dev/null
+++ b/qemu-modinfo.c
@@ -0,0 +1,270 @@
+/*
+ * QEMU module parser
+ *
+ * read modules, find modinfo section, parse & store metadata.
+ *
+ * Copyright Red Hat, Inc. 2021
+ *
+ * Authors:
+ * Gerd Hoffmann 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#include "qemu/osdep.h"
+#include "elf.h"
+#include 
+#include 
+
+#include "qapi/qapi-types-modules.h"
+#include "qapi/qapi-visit-modules.h"
+#include "qapi/qobject-output-visitor.h"
+#include "qapi/qmp/qjson.h"
+#include "qapi/qmp/qstring.h"
+
+#if INTPTR_MAX == INT32_MAX
+# define Elf_Ehdr Elf32_Ehdr
+# define Elf_Shdr Elf32_Shdr
+# define ELFCLASS ELFCLASS32
+#elif INTPTR_MAX == INT64_MAX
+# define Elf_Ehdr Elf64_Ehdr
+# define Elf_Shdr Elf64_Shdr
+# define ELFCLASS ELFCLASS64
+#else
+# error Huh?  Neither 32-bit nor 64-bit host.
+#endif
+
+static const char *moddir = CONFIG_QEMU_MODDIR;
+static const char *dsosuf = CONFIG_HOST_DSOSUF;
+
+static ModuleInfo *modinfo(const char *module, char *info, size_t size)
+{
+ModuleInfo *modinfo;
+strList *sl;
+size_t pos = 0, len;
+
+modinfo = g_new0(ModuleInfo, 1);
+modinfo->name = g_strdup(module);
+
+if (info) {
+do {
+if (strncmp(info + pos, "obj=", 4) == 0) {
+sl = g_new0(strList, 1);
+sl->value = g_strdup(info + pos + 4);
+sl->next = modinfo->objs;
+modinfo->objs = sl;
+modinfo->has_objs = true;
+} else if (strncmp(info + pos, "dep=", 4) == 0) {
+sl = g_new0(strList, 1);
+sl->value = g_strdup(info + pos + 4);
+sl->next = modinfo->deps;
+modinfo->deps = sl;
+modinfo->has_deps = true;
+} else if (strncmp(info + pos, "arch=", 5) == 0) {
+modinfo->arch = g_strdup(info + pos + 5);
+modinfo->has_arch = true;
+} else if (strncmp(info + pos, "opts=", 5) == 0) {
+modinfo->opts = g_strdup(info + pos + 5);
+modinfo->has_opts = true;
+} else {
+fprintf(stderr, "unknown tag: %s\n", info + pos);
+exit(1);
+}
+len = strlen(info + pos) + 1;
+pos += len;
+} while (pos < size);
+}
+
+return modinfo;
+}
+
+static void elf_read_section_hdr(FILE *fp, Elf_Ehdr *ehdr,
+ int section, Elf_Shdr *shdr)
+{
+size_t pos, len;
+int ret;
+
+pos = ehdr->e_shoff + section * ehdr->e_shentsize;
+len = MIN(ehdr->e_shentsize, sizeof(*shdr));
+
+ret = fseek(fp, pos, SEEK_SET);
+if (ret != 0) {
+fprintf(stderr, "seek error\n");
+exit(1);
+}
+
+memset(shdr, 0, sizeof(*shdr));
+ret = fread(shdr, len, 1, fp);
+if (ret != 1) {
+fprintf(stderr, "read error\n");
+exit(1);
+}
+}
+
+static void *elf_read_section(FILE *fp, Elf_Ehdr *ehdr,
+  int section, size_t *size)
+{
+Elf_Shdr shdr;
+void *data;
+int ret;
+
+elf_read_section_hdr(fp, ehdr, section, );
+if (shdr.sh_offset && shdr.sh_size) {
+ret = fseek(fp, shdr.sh_offset, SEEK_SET);
+if (ret != 0) {
+fprintf(stderr, "seek error\n");
+exit(1);
+}
+
+data = g_malloc(shdr.sh_size);
+ret = fread(data, shdr.sh_size, 1, fp);
+if (ret != 1) {
+fprintf(stderr, "read error\n");
+exit(1);
+}
+*size = shdr.sh_size;
+} else {
+data = NULL;
+*size = 0;
+}
+return data;
+}
+
+static ModuleInfo *elf_parse_module(const char *module,
+const char *filename)
+{
+Elf_Ehdr ehdr;
+Elf_Shdr shdr;
+FILE *fp;
+int ret, i;
+char *str;
+size_t str_size;
+char *info;
+size_t info_size;
+
+fp = fopen(filename, "r");
+if (NULL == fp) {
+fprintf(stderr, "open %s: %s\n", filename, strerror(errno));
+exit(1);
+}
+
+ret = fread(, sizeof(ehdr), 1, fp);
+if (ret != 1) {
+fprintf(stderr, "read error (%s)\n", filename);
+exit(1);
+}
+
+if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
+ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
+ehdr.e_ident[EI_MAG3] != ELFMAG3) {
+fprintf(stderr, "not an elf file (%s)\n", filename);
+exit(1);
+}
+if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) {
+   

[PATCH v2 07/18] modules: add usb-redir module annotations

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 hw/usb/redirect.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 6a75b0dc4ab2..4ec9326e0582 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -2608,6 +2608,7 @@ static const TypeInfo usbredir_dev_info = {
 .class_init= usbredir_class_initfn,
 .instance_init = usbredir_instance_init,
 };
+module_obj(TYPE_USB_REDIR);
 
 static void usbredir_register_types(void)
 {
-- 
2.31.1




[PATCH v2 06/18] modules: add audio module annotations

2021-06-10 Thread Gerd Hoffmann
Signed-off-by: Gerd Hoffmann 
---
 audio/spiceaudio.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 999bfbde47c5..a8d370fe6f31 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -317,3 +317,5 @@ static void register_audio_spice(void)
 audio_driver_register(_audio_driver);
 }
 type_init(register_audio_spice);
+
+module_dep("ui-spice-core");
-- 
2.31.1




[PATCH v2 17/18] modules: check arch and block load on mismatch

2021-06-10 Thread Gerd Hoffmann
Add module_allow_arch() to set the target architecture.
In case a module is limited to some arch verify arches
match and ignore the module if not.

Signed-off-by: Gerd Hoffmann 
---
 include/qemu/module.h |  1 +
 softmmu/vl.c  |  3 +++
 util/module.c | 15 +++
 3 files changed, 19 insertions(+)

diff --git a/include/qemu/module.h b/include/qemu/module.h
index d3cab3c25a2f..7825f6d8c847 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -72,6 +72,7 @@ void module_call_init(module_init_type type);
 bool module_load_one(const char *prefix, const char *lib_name, bool mayfail);
 void module_load_qom_one(const char *type);
 void module_load_qom_all(void);
+void module_allow_arch(const char *arch);
 
 /*
  * macros to store module metadata in a .modinfo section.
diff --git a/softmmu/vl.c b/softmmu/vl.c
index ba26a042b284..96316774fcc9 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -126,6 +126,8 @@
 #include "sysemu/iothread.h"
 #include "qemu/guest-random.h"
 
+#include "config-host.h"
+
 #define MAX_VIRTIO_CONSOLES 1
 
 typedef struct BlockdevOptionsQueueEntry {
@@ -2723,6 +2725,7 @@ void qemu_init(int argc, char **argv, char **envp)
 error_init(argv[0]);
 qemu_init_exec_dir(argv[0]);
 
+module_allow_arch(TARGET_NAME);
 qemu_init_subsystems();
 
 /* first pass of option parsing */
diff --git a/util/module.c b/util/module.c
index 6e4199169c41..564b8e3da760 100644
--- a/util/module.c
+++ b/util/module.c
@@ -122,6 +122,12 @@ void module_call_init(module_init_type type)
 static Modules *modinfo;
 static char *module_dirs[5];
 static int module_ndirs;
+static const char *module_arch;
+
+void module_allow_arch(const char *arch)
+{
+module_arch = arch;
+}
 
 static void module_load_path_init(void)
 {
@@ -295,6 +301,14 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail)
 module_load_modinfo();
 
 for (modlist = modinfo->list; modlist != NULL; modlist = modlist->next) {
+if (modlist->value->has_arch) {
+if (strcmp(modlist->value->name, module_name) == 0) {
+if (!module_arch ||
+strcmp(modlist->value->arch, module_arch) != 0) {
+return false;
+}
+}
+}
 if (modlist->value->has_deps) {
 if (strcmp(modlist->value->name, module_name) == 0) {
 /* we depend on other module(s) */
@@ -401,6 +415,7 @@ void qemu_load_module_for_opts(const char *group)
 
 #else
 
+void module_allow_arch(const char *arch) {}
 void qemu_load_module_for_opts(const char *group) {}
 void module_load_qom_one(const char *type) {}
 void module_load_qom_all(void) {}
-- 
2.31.1




[PATCH v2 01/18] modules: add metadata macros, add qxl module annotations

2021-06-10 Thread Gerd Hoffmann
Stealing an idea from the linux kernel:  Place module metadata
in an .modinfo elf section.  This patch adds macros and qxl module
annotations as example.

Signed-off-by: Gerd Hoffmann 
---
 include/qemu/module.h | 22 ++
 hw/display/qxl.c  |  4 
 2 files changed, 26 insertions(+)

diff --git a/include/qemu/module.h b/include/qemu/module.h
index 944d403cbd15..d3cab3c25a2f 100644
--- a/include/qemu/module.h
+++ b/include/qemu/module.h
@@ -73,4 +73,26 @@ bool module_load_one(const char *prefix, const char 
*lib_name, bool mayfail);
 void module_load_qom_one(const char *type);
 void module_load_qom_all(void);
 
+/*
+ * macros to store module metadata in a .modinfo section.
+ * qemu-modinfo utility will collect the metadata.
+ *
+ * Use "objdump -t -s -j .modinfo ${module}.so" to inspect.
+ */
+
+#define ___PASTE(a, b) a##b
+#define __PASTE(a, b) ___PASTE(a, b)
+
+#define modinfo(kind, value) \
+static const char __PASTE(kind, __LINE__)[]  \
+__attribute__((__used__))\
+__attribute__((section(".modinfo"))) \
+__attribute__((aligned(1)))  \
+= stringify(kind) "=" value
+
+#define module_obj(name) modinfo(obj, name)
+#define module_dep(name) modinfo(dep, name)
+#define module_arch(name) modinfo(arch, name)
+#define module_opts(name) modinfo(opts, name)
+
 #endif
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 6e1f8ff1b2a7..84f99088e0a0 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2522,6 +2522,7 @@ static const TypeInfo qxl_primary_info = {
 .parent= TYPE_PCI_QXL,
 .class_init= qxl_primary_class_init,
 };
+module_obj("qxl-vga");
 
 static void qxl_secondary_class_init(ObjectClass *klass, void *data)
 {
@@ -2538,6 +2539,7 @@ static const TypeInfo qxl_secondary_info = {
 .parent= TYPE_PCI_QXL,
 .class_init= qxl_secondary_class_init,
 };
+module_obj("qxl");
 
 static void qxl_register_types(void)
 {
@@ -2547,3 +2549,5 @@ static void qxl_register_types(void)
 }
 
 type_init(qxl_register_types)
+
+module_dep("ui-spice-core");
-- 
2.31.1




<    1   2   3   4   5