Skip to contentSkip to conversation

qemu-system-x86_64 appears to have sgx-epc, but not memory-backend-epc

DISCUSSION Markus Armbruster 5 participants 14 messages Oct 22 – Nov 11

lore
Share & tools
lore
#0 lore raw

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

--> {"execute": "qom-list-types", "arguments": {"implements": "memory-backend"}}
<-- {"return": [{"name": "memory-backend-ram", "parent": "memory-backend"}, {"name": "memory-backend-file", "parent": "memory-backend"}, {"name": "memory-backend-memfd", "parent": "memory-backend"}, {"name": "memory-backend-shm", "parent": "memory-backend"}]}

The example from docs/system/i386/sgx.rst

    Launching a guest
    -----------------

    To launch a SGX guest:

    .. parsed-literal::

      |qemu_system_x86| \\
       -cpu host,+sgx-provisionkey \\
       -object memory-backend-epc,id=mem1,size=64M,prealloc=on \\
       -M sgx-epc.0.memdev=mem1,sgx-epc.0.node=0

does not work:

qemu-system-x86_64: invalid object type: memory-backend-epc

CONFIG_SGX is enabled in my build:

    $ find bld-x86 -name \*.h -exec grep CONFIG_SGX {} +
    bld-x86/x86_64-softmmu-config-devices.h:#define CONFIG_SGX 1
    bld-x86/config-poison.h:#pragma GCC poison CONFIG_SGX
#1 lore raw
Quoted 9 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

Quoted 7 lines
                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

--> {"execute": "qom-list-types", "arguments": {"implements": "memory-backend"}}
<-- {"return": [{"name": "memory-backend-ram", "parent": "memory-backend"}, {"name": "memory-backend-file", "parent": "memory-backend"}, {"name": "memory-backend-memfd", "parent": "memory-backend"}, {"name": "memory-backend-shm", "parent": "memory-backend"}]}

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

With regards,
Daniel

Signature · 3 lines
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
#2 lore raw
Quoted 30 lines · Daniel P. Berrangé
Quoted 5 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

Quoted 8 lines

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

TYPE_MEMORY_BACKEND_MEMFD does the same. I did a quick grep for "calls to type_register not indented by exactly 4 spaces" and I think the other cases are "misindented" or "data-driven type registration" rather than trying to do things conditionally (but I didn't actually look at all of them, instead making guesses based on variable names, so maybe there's one or two more I missed).

I guess maybe this is trying to work around the fact that the memory backend API doesn't give a backend any place to say "this is never going to work" early, because instance_init isn't allowed to fail, these objects aren't TYPE_DEVICE so they don't have "realize", and so the only other option is "fail every alloc call" ?

thanks
-- PMM

#3 lore raw
Quoted 43 lines · Peter Maydell
Quoted 30 lines · Daniel P. Berrangé
Quoted 5 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

Quoted 8 lines

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

TYPE_MEMORY_BACKEND_MEMFD does the same. I did a quick grep for "calls to type_register not indented by exactly 4 spaces" and I think the other cases are "misindented" or "data-driven type registration" rather than trying to do things conditionally (but I didn't actually look at all of them, instead making guesses based on variable names, so maybe there's one or two more I missed).

Quoted 6 lines

I guess maybe this is trying to work around the fact that the memory backend API doesn't give a backend any place to say "this is never going to work" early, because instance_init isn't allowed to fail, these objects aren't TYPE_DEVICE so they don't have "realize", and so the only other option is "fail every alloc call" ?

The memory backends are all implementing the UserCreatable interface, which provides a "complete" method where they could gracefully report lack of the feature via 'errp'.

This is not obvious since UserCreatable is implemented in the parent base class, but the subclasses could provide their own 'complete' impl and chain up the parent impl

m
With regards,
Daniel

Signature · 3 lines
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
#4 lore raw
Quoted 3 lines · Daniel P. Berrangé

The memory backends are all implementing the UserCreatable interface, which provides a "complete" method where they could gracefully report lack of the feature via 'errp'.

I didn't realize UserCreatable was a thing. It seems unfortunate that we have accumulated three different kinds of object creation/destruction life cycle:

- instance_init / instance_finalize
- instance_init / realize / unrealize / instance_finalize
- instance_init / complete / prepare_delete / instance_finalize

-- PMM

#5 lore raw
Quoted 10 lines · Peter Maydell
Quoted 3 lines · Daniel P. Berrangé

The memory backends are all implementing the UserCreatable interface, which provides a "complete" method where they could gracefully report lack of the feature via 'errp'.

I didn't realize UserCreatable was a thing. It seems unfortunate that we have accumulated three different kinds of object creation/destruction life cycle:

- instance_init / instance_finalize

This is all stuff that is supposed to be basic self contanied initialization/cleanup with no side effects or dependencies, and impossible to fail, which is pretty clear semantics. During init, no external properties have been set yet, and during finalize it is already disconnected from the QOM tree. Essentially these should be basic memory allocs/free, mutex inits/destroys, setting default int values if non-zero, etc.

Quoted 2 lines

- instance_init / realize / unrealize / instance_finalize
- instance_init / complete / prepare_delete / instance_finalize

These two have clear overlap in that they both take place after user specified properties have been set, and deal with types of initialization/setup/cleanup that can fail and have external depedencies.

UserCreatable has another aspect in that it is the witness flag for whether a QOM type is permissible to create using -object / object_add.

I've periodically wondered if we could make them the same, but the realize/unrealize phases have significantly more complexity and dependancies than the complete/prepare_delete and most notably, 'realize' has a 'bus' parameter.

I think that an approach to unification would end up with the 'Device' class implementing UserCreatable and providing a 'complete' method which in turn called the 'realize' method. IOW, nothing much would really change in terms of impls, as all Device subclasses would carry on using realize/unrealize. It would merely make Device tree available to -object/object_add. There are probably quite a few edge case problems hiding in there though if one were to actually try to do this, so the pragmatic option is really to ignore this all and accept the different APIs for Device vs non-Device QOM.

With regards,
Daniel

Signature · 3 lines
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
#6 lore raw
Quoted 29 lines · Daniel P. Berrangé
Quoted 10 lines · Peter Maydell
Quoted 3 lines · Daniel P. Berrangé

The memory backends are all implementing the UserCreatable interface, which provides a "complete" method where they could gracefully report lack of the feature via 'errp'.

I didn't realize UserCreatable was a thing. It seems unfortunate that we have accumulated three different kinds of object creation/destruction life cycle:

- instance_init / instance_finalize

This is all stuff that is supposed to be basic self contanied initialization/cleanup with no side effects or dependencies, and impossible to fail, which is pretty clear semantics. During init, no external properties have been set yet, and during finalize it is already disconnected from the QOM tree. Essentially these should be basic memory allocs/free, mutex inits/destroys, setting default int values if non-zero, etc.

Quoted 2 lines

- instance_init / realize / unrealize / instance_finalize
- instance_init / complete / prepare_delete / instance_finalize

These two have clear overlap in that they both take place after user specified properties have been set, and deal with types of initialization/setup/cleanup that can fail and have external depedencies.

Quoted 8 lines

UserCreatable has another aspect in that it is the witness flag for whether a QOM type is permissible to create using -object / object_add.

I've periodically wondered if we could make them the same, but the realize/unrealize phases have significantly more complexity and dependancies than the complete/prepare_delete and most notably, 'realize' has a 'bus' parameter.

No, it doesn't: the method signature is
typedef void (*DeviceRealize)(DeviceState *dev, Error **errp); The qdev_realize() function takes a Bus pointer, but it doesn't get passed to the device itself, only used to call qdev_set_parent_bus(). (So arguably it would be better called "qdev_realize_and_parent()" but that's a bit unwieldy.)

Quoted 10 lines

I think that an approach to unification would end up with the 'Device' class implementing UserCreatable and providing a 'complete' method which in turn called the 'realize' method. IOW, nothing much would really change in terms of impls, as all Device subclasses would carry on using realize/unrealize. It would merely make Device tree available to -object/object_add. There are probably quite a few edge case problems hiding in there though if one were to actually try to do this, so the pragmatic option is really to ignore this all and accept the different APIs for Device vs non-Device QOM.

Probably. But I think the core reason we've ended up here is that we didn't have the two-stage init in the core Object type and so different subclasses have ended up implementing very similar requirements differently. So if we did care enough to tackle this I would favour pushing it up into Object.

-- PMM

#7 lore raw
In reply to Peter Maydell
Quoted 8 lines · Peter Maydell
Quoted 3 lines · Daniel P. Berrangé

The memory backends are all implementing the UserCreatable interface, which provides a "complete" method where they could gracefully report lack of the feature via 'errp'.

I didn't realize UserCreatable was a thing. It seems unfortunate that we have accumulated three different kinds of object creation/destruction life cycle:

Yes. See also "Problem 5: QOM lacks a clear life cycle" in

    Subject: Dynamic & heterogeneous machines, initial configuration: problems
    Date: Wed, 31 Jan 2024 21:14:21 +0100
    Message-ID: <[email protected]>
    https://lore.kernel.org/qemu-devel/[email protected]/    
Quoted 1 line

- instance_init / instance_finalize

All QOM types (but some add to this protocol).

Quoted 1 line

- instance_init / realize / unrealize / instance_finalize

Device types, i.e. subtypes of "device".

Quoted 1 line

- instance_init / complete / prepare_delete / instance_finalize

User-createble object types, i.e. types that provide interface "user-creatable". No device type does that.

Related: machine init done notifiers.

#8 lore raw
In reply to Daniel P. Berrangé
Quoted 51 lines · Daniel P. Berrangé
Quoted 43 lines · Peter Maydell
Quoted 30 lines · Daniel P. Berrangé
Quoted 5 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

Quoted 8 lines

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

TYPE_MEMORY_BACKEND_MEMFD does the same. I did a quick grep for "calls to type_register not indented by exactly 4 spaces" and I think the other cases are "misindented" or "data-driven type registration" rather than trying to do things conditionally (but I didn't actually look at all of them, instead making guesses based on variable names, so maybe there's one or two more I missed).

Quoted 6 lines

I guess maybe this is trying to work around the fact that the memory backend API doesn't give a backend any place to say "this is never going to work" early, because instance_init isn't allowed to fail, these objects aren't TYPE_DEVICE so they don't have "realize", and so the only other option is "fail every alloc call" ?

Quoted 3 lines

The memory backends are all implementing the UserCreatable interface, which provides a "complete" method where they could gracefully report lack of the feature via 'errp'.

Yes.

Quoted 3 lines

This is not obvious since UserCreatable is implemented in the parent base class, but the subclasses could provide their own 'complete' impl and chain up the parent impl

David, Igor, can you clean this up? Or would you like me to try?

#9 lore raw
Quoted 57 lines · On Tue, 27 Oct 2026 07:40:24 +0100 Markus Armbruster <[email protected]> wrote:
Quoted 51 lines · Daniel P. Berrangé
Quoted 43 lines · Peter Maydell
Quoted 30 lines · Daniel P. Berrangé
Quoted 5 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

Quoted 8 lines

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

TYPE_MEMORY_BACKEND_MEMFD does the same. I did a quick grep for "calls to type_register not indented by exactly 4 spaces" and I think the other cases are "misindented" or "data-driven type registration" rather than trying to do things conditionally (but I didn't actually look at all of them, instead making guesses based on variable names, so maybe there's one or two more I missed).

Quoted 6 lines

I guess maybe this is trying to work around the fact that the memory backend API doesn't give a backend any place to say "this is never going to work" early, because instance_init isn't allowed to fail, these objects aren't TYPE_DEVICE so they don't have "realize", and so the only other option is "fail every alloc call" ?

Quoted 3 lines

The memory backends are all implementing the UserCreatable interface, which provides a "complete" method where they could gracefully report lack of the feature via 'errp'.

Quoted 7 lines

Yes.

Quoted 3 lines

This is not obvious since UserCreatable is implemented in the parent base class, but the subclasses could provide their own 'complete' impl and chain up the parent impl

David, Igor, can you clean this up? Or would you like me to try?

Please go ahead, I'm not likely to have bandwidth for upstream ATM.

#10 lore raw
In reply to Peter Maydell
Quoted 35 lines · Peter Maydell
Quoted 30 lines · Daniel P. Berrangé
Quoted 5 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

Quoted 8 lines

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

Quoted 7 lines

TYPE_MEMORY_BACKEND_MEMFD does the same. I did a quick grep for "calls to type_register not indented by exactly 4 spaces" and I think the other cases are "misindented" or "data-driven type registration" rather than trying to do things conditionally (but I didn't actually look at all of them, instead making guesses based on variable names, so maybe there's one or two more I missed).

Alright, I looked. In addition to "misindented" or "data-driven", I found:

* register_types() in hostmem-memfd.c registers "memory-backend-memfd" only when a test of memfd_create() succeeds. This is what Peter reported.

* virtio_ccw_gpu_register() in hw/s390x/virtio-ccw-gpu.c registers "virtio-gpu-ccw" only when have_virtio_ccw, which is true when hw/s390x/virtio-ccw.c gets compiled into the binary. So it's effectively compile-time conditional.

I wish it was literally compile-time conditional, either in meson or using #if.

* qemu_console_early_init() in ui/console-vc.c registers "chardev-vc" if it's not already registered. early_dbus_init() in ui/dbus.c, early_gtk_display_init() in ui/gtk.c, and spice_app_display_early_init() in ui/spice-app.c all register it.

These are all QemuDisplay .early_init() callbacks. qemu_display_early_init() calls the selected display's .early_init(), if non-null.

Because qemu_console_early_init() runs after qemu_display_early_init(), this always registers a "chardev-vc": the active display may register its own, and when it doesn't, we get ui/console-vc.c's.

More moving parts than I'd like.

I'm going to post patches for backends/hostmem-{epc,memfd}.c. I don't plan to clean up the other two at this time.

[...]

#11 lore raw
Quoted 52 lines · Markus Armbruster
Quoted 35 lines · Peter Maydell
Quoted 30 lines · Daniel P. Berrangé
Quoted 5 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

Quoted 8 lines

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

Quoted 7 lines

TYPE_MEMORY_BACKEND_MEMFD does the same. I did a quick grep for "calls to type_register not indented by exactly 4 spaces" and I think the other cases are "misindented" or "data-driven type registration" rather than trying to do things conditionally (but I didn't actually look at all of them, instead making guesses based on variable names, so maybe there's one or two more I missed).

Alright, I looked. In addition to "misindented" or "data-driven", I found:

* register_types() in hostmem-memfd.c registers "memory-backend-memfd" only when a test of memfd_create() succeeds. This is what Peter reported.

Quoted 7 lines

* virtio_ccw_gpu_register() in hw/s390x/virtio-ccw-gpu.c registers "virtio-gpu-ccw" only when have_virtio_ccw, which is true when hw/s390x/virtio-ccw.c gets compiled into the binary. So it's effectively compile-time conditional.

I wish it was literally compile-time conditional, either in meson or using #if.

That looks like it is dead code to me. hw/s390x/meson.build does

hw_s390x_modules = {}
virtio_gpu_ccw_ss = ss.source_set() virtio_gpu_ccw_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_CCW'],

                        if_true: [files('virtio-ccw-gpu.c'), pixman])

hw_s390x_modules += {'virtio-gpu-ccw': virtio_gpu_ccw_ss}

it doesn't look like 'have_virtio_ccw' can ever be false, due to the CONFIG_VIRTIO_CCW Kconfig check ?

Quoted 15 lines

* qemu_console_early_init() in ui/console-vc.c registers "chardev-vc" if it's not already registered. early_dbus_init() in ui/dbus.c, early_gtk_display_init() in ui/gtk.c, and spice_app_display_early_init() in ui/spice-app.c all register it.

These are all QemuDisplay .early_init() callbacks. qemu_display_early_init() calls the selected display's .early_init(), if non-null.

Because qemu_console_early_init() runs after qemu_display_early_init(), this always registers a "chardev-vc": the active display may register its own, and when it doesn't, we get ui/console-vc.c's.

Quoted 7 lines

More moving parts than I'd like.

I'm going to post patches for backends/hostmem-{epc,memfd}.c. I don't plan to clean up the other two at this time.

[...]

With regards,
Daniel

Signature · 3 lines
|: https://berrange.com       ~~        https://hachyderm.io/@berrange :|
|: https://libvirt.org          ~~          https://entangle-photo.org :|
|: https://pixelfed.art/berrange   ~~    https://fstop138.berrange.com :|
#12 lore raw
Quoted 63 lines · Daniel P. Berrangé
Quoted 52 lines · Markus Armbruster
Quoted 35 lines · Peter Maydell
Quoted 30 lines · Daniel P. Berrangé
Quoted 5 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

Quoted 8 lines

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

Quoted 7 lines

TYPE_MEMORY_BACKEND_MEMFD does the same. I did a quick grep for "calls to type_register not indented by exactly 4 spaces" and I think the other cases are "misindented" or "data-driven type registration" rather than trying to do things conditionally (but I didn't actually look at all of them, instead making guesses based on variable names, so maybe there's one or two more I missed).

Alright, I looked. In addition to "misindented" or "data-driven", I found:

* register_types() in hostmem-memfd.c registers "memory-backend-memfd" only when a test of memfd_create() succeeds. This is what Peter reported.

Quoted 7 lines

* virtio_ccw_gpu_register() in hw/s390x/virtio-ccw-gpu.c registers "virtio-gpu-ccw" only when have_virtio_ccw, which is true when hw/s390x/virtio-ccw.c gets compiled into the binary. So it's effectively compile-time conditional.

I wish it was literally compile-time conditional, either in meson or using #if.

That looks like it is dead code to me. hw/s390x/meson.build does

Quoted 8 lines

hw_s390x_modules = {}
virtio_gpu_ccw_ss = ss.source_set() virtio_gpu_ccw_ss.add(when: ['CONFIG_VIRTIO_GPU', 'CONFIG_VIRTIO_CCW'],

                        if_true: [files('virtio-ccw-gpu.c'), pixman])

hw_s390x_modules += {'virtio-gpu-ccw': virtio_gpu_ccw_ss}

it doesn't look like 'have_virtio_ccw' can ever be false, due to the CONFIG_VIRTIO_CCW Kconfig check ?

adcf33a504de ("s390x: modularize virtio-gpu-ccw") seems to indicate that this is needed for virtio-gpu-ccw being a module, not sure if that is still the case.

#13 lore raw
In reply to Daniel P. Berrangé
Quoted 32 lines · Daniel P. Berrangé
Quoted 9 lines · Markus Armbruster

My build of qemu-system-x86_64 has device sgx-epc:

--> {"execute": "qom-list-types", "arguments": {"implements": "sgx-epc"}} <-- {"return": [{"name": "sgx-epc", "parent": "device"}]}

The device as a link property to a memory-backend-epc:

--> {"execute": "qom-list-properties", "arguments": {"typename": "sgx-epc"}} <-- {"return": [...

Quoted 7 lines
                 {"name": "memdev", "type": "link<memory-backend-epc>"},
                 ...]}

However, type memory-backend-epc does not exist:

--> {"execute": "qom-list-types", "arguments": {"implements": "memory-backend"}}
<-- {"return": [{"name": "memory-backend-ram", "parent": "memory-backend"}, {"name": "memory-backend-file", "parent": "memory-backend"}, {"name": "memory-backend-memfd", "parent": "memory-backend"}, {"name": "memory-backend-shm", "parent": "memory-backend"}]}

There is some rather dubious code that conditionally registers the type

static void register_types(void)

{
    int fd = qemu_open_old("/dev/sgx_vepc", O_RDWR);
    if (fd >= 0) {
        close(fd);

        type_register_static(&sgx_epc_backed_info);
    }
}
Quoted 3 lines

Normal practice is for types to be unconditionally registered. Do we have any examples outside of this SGX case where we conditionally
register types ? Should we change this to follow normal practice ?

Loosely related: conditional *class* properties. Example:

    static void
    memfd_backend_class_init(ObjectClass *oc, const void *data)
    {
        HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc);

        bc->alloc = memfd_backend_memory_alloc;

        if (qemu_memfd_check(MFD_HUGETLB)) {
            object_class_property_add_bool(oc, "hugetlb",
                                           memfd_backend_get_hugetlb,
                                           memfd_backend_set_hugetlb);
            object_class_property_set_description(oc, "hugetlb",
                                                  "Use huge pages");
            object_class_property_add(oc, "hugetlbsize", "uint64",
                                      &uint64_type_info,
                                      memfd_backend_get_hugetlbsize,
                                      memfd_backend_set_hugetlbsize,
                                      NULL, NULL);
            object_class_property_set_description(oc, "hugetlbsize",
                                                  "Huge pages size (ex: 2M, 1G)");
        }

        [...]
    }

These properties are also declared in qapi/qom.json if CONFIG_LINUX. QAPI introspection (query-qmp-schema) shows them then. QOM introspection (qom-list-properties etc.) only shows them when the MFD_HUGETLB check succeeded.

Feels undesirable to me.

Should we instead make them read-only when the check fails?