Shameer Kolothum via <qemu-devel@nongnu.org> writes:

> Although this change does not affect functionality at present, it lays
> the groundwork for enabling user-created SMMUv3 devices in
> future patches
>
> Signed-off-by: Shameer Kolothum <shameerali.kolothum.th...@huawei.com>
> ---
>  hw/arm/smmuv3.c | 26 ++++++++++++++++++++++++++
>  hw/arm/virt.c   |  3 ++-
>  2 files changed, 28 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index ab67972353..605de9b721 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -24,6 +24,7 @@
>  #include "hw/qdev-properties.h"
>  #include "hw/qdev-core.h"
>  #include "hw/pci/pci.h"
> +#include "hw/pci/pci_bridge.h"
>  #include "cpu.h"
>  #include "exec/target_page.h"
>  #include "trace.h"
> @@ -1874,6 +1875,25 @@ static void smmu_reset_exit(Object *obj, ResetType 
> type)
>      smmuv3_init_regs(s);
>  }
>  
> +static int smmuv3_pcie_bus(Object *obj, void *opaque)
> +{
> +    DeviceState *d = opaque;
> +    PCIBus *bus;
> +
> +    if (!object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) {
> +        return 0;
> +    }
> +
> +    bus = PCI_HOST_BRIDGE(obj)->bus;
> +    if (d->parent_bus && !strcmp(bus->qbus.name, d->parent_bus->name)) {
> +        object_property_set_link(OBJECT(d), "primary-bus", OBJECT(bus),
> +                                 &error_abort);
> +        /* Return non-zero as we got the bus and don't need further 
> iteration.*/
> +        return 1;
> +    }
> +    return 0;
> +}
> +
>  static void smmu_realize(DeviceState *d, Error **errp)
>  {
>      SMMUState *sys = ARM_SMMU(d);
> @@ -1882,6 +1902,10 @@ static void smmu_realize(DeviceState *d, Error **errp)
>      SysBusDevice *dev = SYS_BUS_DEVICE(d);
>      Error *local_err = NULL;
>  
> +    if (!object_property_get_link(OBJECT(d), "primary-bus", &error_abort)) {
> +        object_child_foreach_recursive(object_get_root(), smmuv3_pcie_bus, 
> d);
> +    }
> +
>      c->parent_realize(d, &local_err);
>      if (local_err) {
>          error_propagate(errp, local_err);
> @@ -1996,6 +2020,8 @@ static void smmuv3_class_init(ObjectClass *klass, const 
> void *data)
>      device_class_set_parent_realize(dc, smmu_realize,
>                                      &c->parent_realize);
>      device_class_set_props(dc, smmuv3_properties);
> +    dc->hotpluggable = false;
> +    dc->bus_type = TYPE_PCIE_BUS;

This is very, very wrong.

The function serves as .class_init() for QOM type "arm-smmuv3", defined
as:

   static const TypeInfo smmuv3_type_info = {
       .name          = TYPE_ARM_SMMUV3,
       .parent        = TYPE_ARM_SMMU,

Subtype of "arm-smmuv3".

       .instance_size = sizeof(SMMUv3State),
       .instance_init = smmuv3_instance_init,
       .class_size    = sizeof(SMMUv3Class),
       .class_init    = smmuv3_class_init,
   };


    static const TypeInfo smmu_base_info = {
        .name          = TYPE_ARM_SMMU,
        .parent        = TYPE_SYS_BUS_DEVICE,

Subtype of "sys-bus-device".

        .instance_size = sizeof(SMMUState),
        .class_data    = NULL,
        .class_size    = sizeof(SMMUBaseClass),
        .class_init    = smmu_base_class_init,
        .abstract      = true,
    };

Have a look at the instance struct:

   struct SMMUv3State {
       SMMUState     smmu_state;

Starts with the supertype's instance struct, as is proper.

       uint32_t features;
       [more ...]
   };

Here's the supertype's instance struct:

   struct SMMUState {
       /* <private> */
       SysBusDevice  dev;

Again, starts with the supertype's instance struct.

       const char *mrtypename;
       [more...]
   };

This is a sysbus device, not a PCI device.  Monkey-patching dc->bus_type
from TYPE_SYSTEM_BUS to TYPE_PCIE_BUS won't change that.  All it
accomplishes is making the qdev core believe it plugs into a PCIE bus.
This can only end in tears.

In fact, when I build with the entire series applied (so the device can
actually be used with -device), the result dies within seconds of my ad
hoc testing:

    $ qemu-system-aarch64 -nodefaults -S -display none -monitor stdio -M virt 
-device pxb-pcie,id=pcie.1,bus_nr=2 -device arm-smmuv3,bus=pcie.1
    QEMU 10.0.50 monitor - type 'help' for more information
    qemu-system-aarch64: -device arm-smmuv3,bus=pcie.1: warning: SMMUv3 device 
only supported with pcie.0 for DT
    (qemu) info qtree
    bus: main-system-bus
      type System
      dev: pxb-host, id ""
        x-config-reg-migration-enabled = true
        bypass-iommu = false
        bus: pcie.1
          type pxb-pcie-bus
          dev: arm-smmuv3, id ""
            gpio-out "sysbus-irq" 4
            stage = "nested"
            bus_num = 0 (0x0)
    Segmentation fault (core dumped)

Backtrace:

    #0  0x00005555557d8521 in pcibus_dev_print
        (mon=0x55555826d0e0, dev=0x5555590ad360, indent=8)
        at ../hw/pci/pci-hmp-cmds.c:140
    #1  0x0000555555eac0a0 in bus_print_dev
        (bus=<optimized out>, mon=<optimized out>, dev=0x5555590ad360, indent=8)
        at ../system/qdev-monitor.c:773
    #2  qdev_print (mon=<optimized out>, dev=<optimized out>, indent=8)
        at ../system/qdev-monitor.c:805
    #3  qbus_print
        (mon=mon@entry=0x55555826d0e0, bus=bus@entry=0x5555590ac4a0, indent=6, 
        indent@entry=4, details=details@entry=true) at 
../system/qdev-monitor.c:821
    #4  0x0000555555eabd92 in qbus_print
        (mon=0x55555826d0e0, bus=<optimized out>, indent=2, details=true)
        at ../system/qdev-monitor.c:824
    #5  0x0000555555979789 in handle_hmp_command_exec
        (cmd=<optimized out>, mon=0x55555826d0e0, qdict=0x55555907d8e0)
        at ../monitor/hmp.c:1106
    #6  handle_hmp_command_exec
        (mon=0x55555826d0e0, cmd=0x55555769d220 <hmp_info_cmds+2560>, 
qdict=0x55555907d8e0) at ../monitor/hmp.c:1098
    #7  handle_hmp_command (mon=mon@entry=0x55555826d0e0, cmdline=<optimized 
out>, 
        cmdline@entry=0x555558657490 "info qtree") at ../monitor/hmp.c:1158
    #8  0x000055555597983c in monitor_command_cb

Crash line is

    int class = pci_get_word(d->config + PCI_CLASS_DEVICE);

Debugger shows that d->config is invalid.  This is hardly surprising!

The qdev core is trying to print information on the "arm_smmuv3" device
here.  It's working with a DeviceState.  Your monkey-patching convinced
it it's a PCIDevice, so it duly calls pcibus_dev_print() to print PCI
device information.  pcibus_dev_print() casts the DeviceState * to
PCIDevice *.  This assumes the device's instance actually starts with
PCIDevice.  It actually starts with SysBusDevice.

Unsurprisingly, and "make check" also fails:

    >>> MESON_TEST_ITERATION=1 
MSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
 RUST_BACKTRACE=1 QTEST_QEMU_BINARY=./qemu-system-aarch64 
QTEST_QEMU_IMG=./qemu-img 
G_TEST_DBUS_DAEMON=/work/armbru/qemu/tests/dbus-vmstate-daemon.sh 
ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 
PYTHON=/work/armbru/qemu/bld-arm/pyvenv/bin/python3 
UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
 MALLOC_PERTURB_=22 /work/armbru/qemu/bld-arm/tests/qtest/test-hmp --tap -k
    ――――――――――――――――――――――――――――――――――――― ✀  
―――――――――――――――――――――――――――――――――――――
    stderr:
    qemu-system-aarch64: ../hw/core/qdev.c:113: qdev_set_parent_bus: Assertion 
`dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)' failed.
    Broken pipe
    ../tests/qtest/libqtest.c:208: kill_qemu() detected QEMU death from signal 
6 (Aborted) (core dumped)

and

    >>> MESON_TEST_ITERATION=1 
MSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
 RUST_BACKTRACE=1 QTEST_QEMU_BINARY=./qemu-system-aarch64 MALLOC_PERTURB_=86 
QTEST_QEMU_IMG=./qemu-img 
G_TEST_DBUS_DAEMON=/work/armbru/qemu/tests/dbus-vmstate-daemon.sh 
ASAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1 
PYTHON=/work/armbru/qemu/bld-arm/pyvenv/bin/python3 
UBSAN_OPTIONS=halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1
 /work/armbru/qemu/bld-arm/tests/qtest/qom-test --tap -k
    ――――――――――――――――――――――――――――――――――――― ✀  
―――――――――――――――――――――――――――――――――――――
    stderr:
    qemu-system-aarch64: ../hw/core/qdev.c:113: qdev_set_parent_bus: Assertion 
`dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)' failed.
    Broken pipe
    ../tests/qtest/libqtest.c:208: kill_qemu() detected QEMU death from signal 
6 (Aborted) (core dumped)

Please make sure "make check" passes before posting patches for review.
If you need help getting there, post them marked RFC and with the bad
test results right in the cover letter.

>  }
>  
>  static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu,
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 177f3dd22c..3bae4e374f 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -56,6 +56,7 @@
>  #include "qemu/cutils.h"
>  #include "qemu/error-report.h"
>  #include "qemu/module.h"
> +#include "hw/pci/pci_bus.h"
>  #include "hw/pci-host/gpex.h"
>  #include "hw/virtio/virtio-pci.h"
>  #include "hw/core/sysbus-fdt.h"
> @@ -1442,7 +1443,7 @@ static void create_smmu(const VirtMachineState *vms,
>      }
>      object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
>                               &error_abort);
> -    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +    qdev_realize_and_unref(dev, &bus->qbus, &error_fatal);
>      sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
>      for (i = 0; i < NUM_SMMU_IRQS; i++) {
>          sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,

What are you trying to accomplish?

I *guess* you're trying to change the "arm-smmuv3" device to be a PCI
device.  Correct?

The only way to do that is making it a subtype of PCIDevice, i.e. change
the parent chain from

   arm-smmuv3 -> arm-smmu -> sys-bus-device -> device -> object

to something like

   arm-smmuv3 ->    ...   -> pci-device -> device -> object

Note you cannot have different subtypes of the same supertype (say
"arm-smmu") plug into different buses.  If you need a common device core
to plug into different buses, things get more complicated.  Here's how
the "serial-FOO" devices do it:

* "serial-mm", a subtype of "sys-bus-device", thus plugs into system bus
* "serial-isa", a subtype of "isa-device", thus plugs into ISA bus
* "serial-pci", a subtype of "pci-device", thus plugs into PCI bus

They all *contain* the core "serial" device, which is a subtype of
"device", and thus does not plug into any bus.  "Contain" is "has a",
not "subtype of".

[...]


Reply via email to