diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-03-13 12:32:47 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-03-13 12:32:47 +0000 |
commit | c8d146aecceb560664b112279ffddf6fe1db99db (patch) | |
tree | ee6ad1ab9701df1b9fb69be823b0a6ac9cd03933 | |
parent | 0100f42550201f346cc0c20c1864f941509eb592 (diff) | |
parent | f8762027a33e2f5d0915c56a904962b1481f75c1 (diff) | |
download | qemu-c8d146aecceb560664b112279ffddf6fe1db99db.zip qemu-c8d146aecceb560664b112279ffddf6fe1db99db.tar.gz qemu-c8d146aecceb560664b112279ffddf6fe1db99db.tar.bz2 |
Merge remote-tracking branch 'remotes/afaerber/tags/qom-devices-for-peter' into staging
QOM/QTest infrastructure fixes and device conversions
* QTest cleanups and test cases for some virtio devices
* QTest for sPAPR PCI host bridge
* qom-test now tests reading all properties beneath /machine
* QOM API leak fixes
* QOM cleanups for SSI devices
* QOM conversion of QEMUMachine
* QOM realize for buses
* sPAPR PCI bus name change
# gpg: Signature made Thu 13 Mar 2014 00:22:40 GMT using RSA key ID 3E7E013F
# gpg: Good signature from "Andreas Färber <afaerber@suse.de>"
# gpg: aka "Andreas Färber <afaerber@suse.com>"
* remotes/afaerber/tags/qom-devices-for-peter: (31 commits)
libqtest: Fix possible deadlock in qtest initialization
pci: Move VMState registration/unregistration to QOM realize/unrealize
qdev: Realize buses on device realization
qdev: Prepare realize/unrealize hooks for BusState
tests: Add spapr-pci-host-bridge qtest
virtio-serial-port: Convert to QOM realize/unrealize
virtio-console: QOM cast cleanup for VirtConsole
tests: Add virtio-console qtest
tests: Add virtio-serial qtest
tests: Add virtio-scsi qtest
tests: Add virtio-rng qtest
tests: Add virtio-balloon qtest
tests: Add virtio-blk qtest
tests: Clean up IndustryPack TPCI200 gcov paths
qom-test: Test QOM properties
hw/boards: Convert current_machine to MachineState
vl: Use MachineClass instead of global QEMUMachine list
hw/core: Introduce QEMU machine as QOM object
qdev-monitor-test: Don't test human-readable error message
qdev-monitor-test: Simplify using g_assert_cmpstr()
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
34 files changed, 753 insertions, 216 deletions
diff --git a/device-hotplug.c b/device-hotplug.c index 103d34a..ebfa6b1 100644 --- a/device-hotplug.c +++ b/device-hotplug.c @@ -33,12 +33,14 @@ DriveInfo *add_init_drive(const char *optstr) { DriveInfo *dinfo; QemuOpts *opts; + MachineClass *mc; opts = drive_def(optstr); if (!opts) return NULL; - dinfo = drive_init(opts, current_machine->block_default_type); + mc = MACHINE_GET_CLASS(current_machine); + dinfo = drive_init(opts, mc->qemu_machine->block_default_type); if (!dinfo) { qemu_opts_del(opts); return NULL; diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c index 2decff1..392ca84 100644 --- a/hw/arm/spitz.c +++ b/hw/arm/spitz.c @@ -658,14 +658,15 @@ static void spitz_adc_temp_on(void *opaque, int line, int level) max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); } -static int corgi_ssp_init(SSISlave *dev) +static int corgi_ssp_init(SSISlave *d) { - CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, dev); + DeviceState *dev = DEVICE(d); + CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d); - qdev_init_gpio_in(&dev->qdev, corgi_ssp_gpio_cs, 3); - s->bus[0] = ssi_create_bus(&dev->qdev, "ssi0"); - s->bus[1] = ssi_create_bus(&dev->qdev, "ssi1"); - s->bus[2] = ssi_create_bus(&dev->qdev, "ssi2"); + qdev_init_gpio_in(dev, corgi_ssp_gpio_cs, 3); + s->bus[0] = ssi_create_bus(dev, "ssi0"); + s->bus[1] = ssi_create_bus(dev, "ssi1"); + s->bus[2] = ssi_create_bus(dev, "ssi2"); return 0; } diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 02a1544..e29a738 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -241,7 +241,8 @@ typedef enum { } CMDState; typedef struct Flash { - SSISlave ssidev; + SSISlave parent_obj; + uint32_t r; BlockDriverState *bdrv; @@ -545,7 +546,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) static int m25p80_cs(SSISlave *ss, bool select) { - Flash *s = FROM_SSI_SLAVE(Flash, ss); + Flash *s = M25P80(ss); if (select) { s->len = 0; @@ -561,7 +562,7 @@ static int m25p80_cs(SSISlave *ss, bool select) static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) { - Flash *s = FROM_SSI_SLAVE(Flash, ss); + Flash *s = M25P80(ss); uint32_t r = 0; switch (s->state) { @@ -610,7 +611,7 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) static int m25p80_init(SSISlave *ss) { DriveInfo *dinfo; - Flash *s = FROM_SSI_SLAVE(Flash, ss); + Flash *s = M25P80(ss); M25P80Class *mc = M25P80_GET_CLASS(s); s->pi = mc->pi; diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 2e00ad2..ffd29a8 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -15,8 +15,13 @@ #include "trace.h" #include "hw/virtio/virtio-serial.h" +#define TYPE_VIRTIO_CONSOLE "virtconsole" +#define VIRTIO_CONSOLE(obj) \ + OBJECT_CHECK(VirtConsole, (obj), TYPE_VIRTIO_CONSOLE) + typedef struct VirtConsole { - VirtIOSerialPort port; + VirtIOSerialPort parent_obj; + CharDriverState *chr; guint watch; } VirtConsole; @@ -31,7 +36,7 @@ static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond, VirtConsole *vcon = opaque; vcon->watch = 0; - virtio_serial_throttle_port(&vcon->port, false); + virtio_serial_throttle_port(VIRTIO_SERIAL_PORT(vcon), false); return FALSE; } @@ -39,7 +44,7 @@ static gboolean chr_write_unblocked(GIOChannel *chan, GIOCondition cond, static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, ssize_t len) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + VirtConsole *vcon = VIRTIO_CONSOLE(port); ssize_t ret; if (!vcon->chr) { @@ -75,7 +80,7 @@ static ssize_t flush_buf(VirtIOSerialPort *port, /* Callback function that's called when the guest opens/closes the port */ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + VirtConsole *vcon = VIRTIO_CONSOLE(port); if (!vcon->chr) { return; @@ -88,45 +93,49 @@ static int chr_can_read(void *opaque) { VirtConsole *vcon = opaque; - return virtio_serial_guest_ready(&vcon->port); + return virtio_serial_guest_ready(VIRTIO_SERIAL_PORT(vcon)); } /* Send data from a char device over to the guest */ static void chr_read(void *opaque, const uint8_t *buf, int size) { VirtConsole *vcon = opaque; + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon); - trace_virtio_console_chr_read(vcon->port.id, size); - virtio_serial_write(&vcon->port, buf, size); + trace_virtio_console_chr_read(port->id, size); + virtio_serial_write(port, buf, size); } static void chr_event(void *opaque, int event) { VirtConsole *vcon = opaque; + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(vcon); - trace_virtio_console_chr_event(vcon->port.id, event); + trace_virtio_console_chr_event(port->id, event); switch (event) { case CHR_EVENT_OPENED: - virtio_serial_open(&vcon->port); + virtio_serial_open(port); break; case CHR_EVENT_CLOSED: if (vcon->watch) { g_source_remove(vcon->watch); vcon->watch = 0; } - virtio_serial_close(&vcon->port); + virtio_serial_close(port); break; } } -static int virtconsole_initfn(VirtIOSerialPort *port) +static void virtconsole_realize(DeviceState *dev, Error **errp) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); - VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port); + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); + VirtConsole *vcon = VIRTIO_CONSOLE(dev); + VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(dev); if (port->id == 0 && !k->is_console) { - error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility."); - return -1; + error_setg(errp, "Port number 0 on virtio-serial devices reserved " + "for virtconsole devices for backward compatibility."); + return; } if (vcon->chr) { @@ -134,19 +143,15 @@ static int virtconsole_initfn(VirtIOSerialPort *port) qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, vcon); } - - return 0; } -static int virtconsole_exitfn(VirtIOSerialPort *port) +static void virtconsole_unrealize(DeviceState *dev, Error **errp) { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + VirtConsole *vcon = VIRTIO_CONSOLE(dev); if (vcon->watch) { g_source_remove(vcon->watch); } - - return 0; } static Property virtconsole_properties[] = { @@ -160,15 +165,15 @@ static void virtconsole_class_init(ObjectClass *klass, void *data) VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); k->is_console = true; - k->init = virtconsole_initfn; - k->exit = virtconsole_exitfn; + k->realize = virtconsole_realize; + k->unrealize = virtconsole_unrealize; k->have_data = flush_buf; k->set_guest_connected = set_guest_connected; dc->props = virtconsole_properties; } static const TypeInfo virtconsole_info = { - .name = "virtconsole", + .name = TYPE_VIRTIO_CONSOLE, .parent = TYPE_VIRTIO_SERIAL_PORT, .instance_size = sizeof(VirtConsole), .class_init = virtconsole_class_init, @@ -184,8 +189,8 @@ static void virtserialport_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); - k->init = virtconsole_initfn; - k->exit = virtconsole_exitfn; + k->realize = virtconsole_realize; + k->unrealize = virtconsole_unrealize; k->have_data = flush_buf; k->set_guest_connected = set_guest_connected; dc->props = virtserialport_properties; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 226e9f9..2b647b6 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -808,13 +808,14 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id) send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1); } -static int virtser_port_qdev_init(DeviceState *qdev) +static void virtser_port_device_realize(DeviceState *dev, Error **errp) { - VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev); + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); - VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus); - int ret, max_nr_ports; + VirtIOSerialBus *bus = VIRTIO_SERIAL_BUS(qdev_get_parent_bus(dev)); + int max_nr_ports; bool plugging_port0; + Error *err = NULL; port->vser = bus->vser; port->bh = qemu_bh_new(flush_queued_data_bh, port); @@ -829,9 +830,9 @@ static int virtser_port_qdev_init(DeviceState *qdev) plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0); if (find_port_by_id(port->vser, port->id)) { - error_report("virtio-serial-bus: A port already exists at id %u", - port->id); - return -1; + error_setg(errp, "virtio-serial-bus: A port already exists at id %u", + port->id); + return; } if (port->id == VIRTIO_CONSOLE_BAD_ID) { @@ -840,22 +841,24 @@ static int virtser_port_qdev_init(DeviceState *qdev) } else { port->id = find_free_port_id(port->vser); if (port->id == VIRTIO_CONSOLE_BAD_ID) { - error_report("virtio-serial-bus: Maximum port limit for this device reached"); - return -1; + error_setg(errp, "virtio-serial-bus: Maximum port limit for " + "this device reached"); + return; } } } max_nr_ports = tswap32(port->vser->config.max_nr_ports); if (port->id >= max_nr_ports) { - error_report("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u", - max_nr_ports - 1); - return -1; + error_setg(errp, "virtio-serial-bus: Out-of-range port id specified, " + "max. allowed: %u", max_nr_ports - 1); + return; } - ret = vsc->init(port); - if (ret) { - return ret; + vsc->realize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; } port->elem.out_num = 0; @@ -868,14 +871,12 @@ static int virtser_port_qdev_init(DeviceState *qdev) /* Send an update to the guest about this new port added */ virtio_notify_config(VIRTIO_DEVICE(port->vser)); - - return ret; } -static int virtser_port_qdev_exit(DeviceState *qdev) +static void virtser_port_device_unrealize(DeviceState *dev, Error **errp) { - VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev); - VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); + VirtIOSerialPort *port = VIRTIO_SERIAL_PORT(dev); + VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(dev); VirtIOSerial *vser = port->vser; qemu_bh_delete(port->bh); @@ -883,10 +884,9 @@ static int virtser_port_qdev_exit(DeviceState *qdev) QTAILQ_REMOVE(&vser->ports, port, next); - if (vsc->exit) { - vsc->exit(port); + if (vsc->unrealize) { + vsc->unrealize(dev, errp); } - return 0; } static void virtio_serial_device_realize(DeviceState *dev, Error **errp) @@ -971,10 +971,11 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) static void virtio_serial_port_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); - k->init = virtser_port_qdev_init; + set_bit(DEVICE_CATEGORY_INPUT, k->categories); k->bus_type = TYPE_VIRTIO_SERIAL_BUS; - k->exit = virtser_port_qdev_exit; + k->realize = virtser_port_device_realize; + k->unrealize = virtser_port_device_unrealize; k->unplug = qdev_simple_unplug_cb; k->props = virtser_props; } diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index 9e324be..981593c 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -8,7 +8,7 @@ common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_SOFTMMU) += sysbus.o +common-obj-$(CONFIG_SOFTMMU) += machine.o common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o - diff --git a/hw/core/machine.c b/hw/core/machine.c new file mode 100644 index 0000000..d3ffef7 --- /dev/null +++ b/hw/core/machine.c @@ -0,0 +1,28 @@ +/* + * QEMU Machine + * + * Copyright (C) 2014 Red Hat Inc + * + * Authors: + * Marcel Apfelbaum <marcel.a@redhat.com> + * + * 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 "hw/boards.h" + +static const TypeInfo machine_info = { + .name = TYPE_MACHINE, + .parent = TYPE_OBJECT, + .abstract = true, + .class_size = sizeof(MachineClass), + .instance_size = sizeof(MachineState), +}; + +static void machine_register_types(void) +{ + type_register_static(&machine_info); +} + +type_init(machine_register_types) diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 380976a..9f0a522 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -501,6 +501,45 @@ static void bus_unparent(Object *obj) } } +static bool bus_get_realized(Object *obj, Error **err) +{ + BusState *bus = BUS(obj); + + return bus->realized; +} + +static void bus_set_realized(Object *obj, bool value, Error **err) +{ + BusState *bus = BUS(obj); + BusClass *bc = BUS_GET_CLASS(bus); + Error *local_err = NULL; + + if (value && !bus->realized) { + if (bc->realize) { + bc->realize(bus, &local_err); + + if (local_err != NULL) { + goto error; + } + + } + } else if (!value && bus->realized) { + if (bc->unrealize) { + bc->unrealize(bus, &local_err); + + if (local_err != NULL) { + goto error; + } + } + } + + bus->realized = value; + return; + +error: + error_propagate(err, local_err); +} + void qbus_create_inplace(void *bus, size_t size, const char *typename, DeviceState *parent, const char *name) { @@ -677,6 +716,7 @@ static void device_set_realized(Object *obj, bool value, Error **err) { DeviceState *dev = DEVICE(obj); DeviceClass *dc = DEVICE_GET_CLASS(dev); + BusState *bus; Error *local_err = NULL; if (dev->hotplugged && !dc->hotpluggable) { @@ -710,14 +750,30 @@ static void device_set_realized(Object *obj, bool value, Error **err) dev->instance_id_alias, dev->alias_required_for_version); } + if (local_err == NULL) { + QLIST_FOREACH(bus, &dev->child_bus, sibling) { + object_property_set_bool(OBJECT(bus), true, "realized", + &local_err); + if (local_err != NULL) { + break; + } + } + } if (dev->hotplugged && local_err == NULL) { device_reset(dev); } } else if (!value && dev->realized) { - if (qdev_get_vmsd(dev)) { + QLIST_FOREACH(bus, &dev->child_bus, sibling) { + object_property_set_bool(OBJECT(bus), false, "realized", + &local_err); + if (local_err != NULL) { + break; + } + } + if (qdev_get_vmsd(dev) && local_err == NULL) { vmstate_unregister(dev, qdev_get_vmsd(dev), dev); } - if (dc->unrealize) { + if (dc->unrealize && local_err == NULL) { dc->unrealize(dev, &local_err); } } @@ -735,7 +791,8 @@ static bool device_get_hotpluggable(Object *obj, Error **err) DeviceClass *dc = DEVICE_GET_CLASS(obj); DeviceState *dev = DEVICE(obj); - return dc->hotpluggable && dev->parent_bus->allow_hotplug; + return dc->hotpluggable && (dev->parent_bus == NULL || + dev->parent_bus->allow_hotplug); } static void device_initfn(Object *obj) @@ -792,14 +849,6 @@ static void device_class_base_init(ObjectClass *class, void *data) * so do not propagate them to the subclasses. */ klass->props = NULL; - - /* by default all devices were considered as hotpluggable, - * so with intent to check it in generic qdev_unplug() / - * device_set_realized() functions make every device - * hotpluggable. Devices that shouldn't be hotpluggable, - * should override it in their class_init() - */ - klass->hotpluggable = true; } static void device_unparent(Object *obj) @@ -809,13 +858,13 @@ static void device_unparent(Object *obj) QObject *event_data; bool have_realized = dev->realized; + if (dev->realized) { + object_property_set_bool(obj, false, "realized", NULL); + } while (dev->num_child_bus) { bus = QLIST_FIRST(&dev->child_bus); object_unparent(OBJECT(bus)); } - if (dev->realized) { - object_property_set_bool(obj, false, "realized", NULL); - } if (dev->parent_bus) { bus_remove_child(dev->parent_bus, dev); object_unref(OBJECT(dev->parent_bus)); @@ -845,6 +894,14 @@ static void device_class_init(ObjectClass *class, void *data) class->unparent = device_unparent; dc->realize = device_realize; dc->unrealize = device_unrealize; + + /* by default all devices were considered as hotpluggable, + * so with intent to check it in generic qdev_unplug() / + * device_set_realized() functions make every device + * hotpluggable. Devices that shouldn't be hotpluggable, + * should override it in their class_init() + */ + dc->hotpluggable = true; } void device_reset(DeviceState *dev) @@ -888,6 +945,8 @@ static void qbus_initfn(Object *obj) object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, TYPE_HOTPLUG_HANDLER, (Object **)&bus->hotplug_handler, NULL); + object_property_add_bool(obj, "realized", + bus_get_realized, bus_set_realized, NULL); } static char *default_bus_get_fw_dev_path(DeviceState *dev) diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c index 5da3dc5..85252a2 100644 --- a/hw/display/ads7846.c +++ b/hw/display/ads7846.c @@ -133,11 +133,12 @@ static const VMStateDescription vmstate_ads7846 = { } }; -static int ads7846_init(SSISlave *dev) +static int ads7846_init(SSISlave *d) { - ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, dev); + DeviceState *dev = DEVICE(d); + ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d); - qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1); + qdev_init_gpio_out(dev, &s->interrupt, 1); s->input[0] = ADS_TEMP0; /* TEMP0 */ s->input[2] = ADS_VBAT; /* VBAT */ diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 46c3b40..971152e 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -336,18 +336,19 @@ static const GraphicHwOps ssd0323_ops = { .gfx_update = ssd0323_update_display, }; -static int ssd0323_init(SSISlave *dev) +static int ssd0323_init(SSISlave *d) { - ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, dev); + DeviceState *dev = DEVICE(d); + ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d); s->col_end = 63; s->row_end = 79; - s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s); + s->con = graphic_console_init(dev, 0, &ssd0323_ops, s); qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY); - qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1); + qdev_init_gpio_in(dev, ssd0323_cd, 1); - register_savevm(&dev->qdev, "ssd0323_oled", -1, 1, + register_savevm(dev, "ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s); return 0; } diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c index d477ecd..bba87c2 100644 --- a/hw/misc/max111x.c +++ b/hw/misc/max111x.c @@ -13,7 +13,8 @@ #include "hw/ssi.h" typedef struct { - SSISlave ssidev; + SSISlave parent_obj; + qemu_irq interrupt; uint8_t tb1, rb2, rb3; int cycle; @@ -22,6 +23,14 @@ typedef struct { int inputs, com; } MAX111xState; +#define TYPE_MAX_111X "max111x" + +#define MAX_111X(obj) \ + OBJECT_CHECK(MAX111xState, (obj), TYPE_MAX_111X) + +#define TYPE_MAX_1110 "max1110" +#define TYPE_MAX_1111 "max1111" + /* Control-byte bitfields */ #define CB_PD0 (1 << 0) #define CB_PD1 (1 << 1) @@ -92,7 +101,7 @@ static void max111x_write(MAX111xState *s, uint32_t value) static uint32_t max111x_transfer(SSISlave *dev, uint32_t value) { - MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev); + MAX111xState *s = MAX_111X(dev); max111x_write(s, value); return max111x_read(s); } @@ -103,7 +112,7 @@ static const VMStateDescription vmstate_max111x = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_SSI_SLAVE(ssidev, MAX111xState), + VMSTATE_SSI_SLAVE(parent_obj, MAX111xState), VMSTATE_UINT8(tb1, MAX111xState), VMSTATE_UINT8(rb2, MAX111xState), VMSTATE_UINT8(rb3, MAX111xState), @@ -115,11 +124,12 @@ static const VMStateDescription vmstate_max111x = { } }; -static int max111x_init(SSISlave *dev, int inputs) +static int max111x_init(SSISlave *d, int inputs) { - MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, dev); + DeviceState *dev = DEVICE(d); + MAX111xState *s = MAX_111X(dev); - qdev_init_gpio_out(&dev->qdev, &s->interrupt, 1); + qdev_init_gpio_out(dev, &s->interrupt, 1); s->inputs = inputs; /* TODO: add a user interface for setting these */ @@ -133,7 +143,7 @@ static int max111x_init(SSISlave *dev, int inputs) s->input[7] = 0x80; s->com = 0; - vmstate_register(&dev->qdev, -1, &vmstate_max111x, s); + vmstate_register(dev, -1, &vmstate_max111x, s); return 0; } @@ -149,23 +159,36 @@ static int max1111_init(SSISlave *dev) void max111x_set_input(DeviceState *dev, int line, uint8_t value) { - MAX111xState *s = FROM_SSI_SLAVE(MAX111xState, SSI_SLAVE_FROM_QDEV(dev)); + MAX111xState *s = MAX_111X(dev); assert(line >= 0 && line < s->inputs); s->input[line] = value; } -static void max1110_class_init(ObjectClass *klass, void *data) +static void max111x_class_init(ObjectClass *klass, void *data) { SSISlaveClass *k = SSI_SLAVE_CLASS(klass); - k->init = max1110_init; k->transfer = max111x_transfer; } -static const TypeInfo max1110_info = { - .name = "max1110", +static const TypeInfo max111x_info = { + .name = TYPE_MAX_111X, .parent = TYPE_SSI_SLAVE, .instance_size = sizeof(MAX111xState), + .class_init = max111x_class_init, + .abstract = true, +}; + +static void max1110_class_init(ObjectClass *klass, void *data) +{ + SSISlaveClass *k = SSI_SLAVE_CLASS(klass); + + k->init = max1110_init; +} + +static const TypeInfo max1110_info = { + .name = TYPE_MAX_1110, + .parent = TYPE_MAX_111X, .class_init = max1110_class_init, }; @@ -174,18 +197,17 @@ static void max1111_class_init(ObjectClass *klass, void *data) SSISlaveClass *k = SSI_SLAVE_CLASS(klass); k->init = max1111_init; - k->transfer = max111x_transfer; } static const TypeInfo max1111_info = { - .name = "max1111", - .parent = TYPE_SSI_SLAVE, - .instance_size = sizeof(MAX111xState), + .name = TYPE_MAX_1111, + .parent = TYPE_MAX_111X, .class_init = max1111_class_init, }; static void max111x_register_types(void) { + type_register_static(&max111x_info); type_register_static(&max1110_info); type_register_static(&max1111_info); } diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 4e0701d..8f722dd 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -48,7 +48,6 @@ static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); static void pcibus_reset(BusState *qbus); -static void pci_bus_finalize(Object *obj); static Property pci_props[] = { DEFINE_PROP_PCI_DEVFN("addr", PCIDevice, devfn, -1), @@ -61,6 +60,34 @@ static Property pci_props[] = { DEFINE_PROP_END_OF_LIST() }; +static const VMStateDescription vmstate_pcibus = { + .name = "PCIBUS", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField[]) { + VMSTATE_INT32_EQUAL(nirq, PCIBus), + VMSTATE_VARRAY_INT32(irq_count, PCIBus, + nirq, 0, vmstate_info_int32, + int32_t), + VMSTATE_END_OF_LIST() + } +}; + +static void pci_bus_realize(BusState *qbus, Error **errp) +{ + PCIBus *bus = PCI_BUS(qbus); + + vmstate_register(NULL, -1, &vmstate_pcibus, bus); +} + +static void pci_bus_unrealize(BusState *qbus, Error **errp) +{ + PCIBus *bus = PCI_BUS(qbus); + + vmstate_unregister(NULL, &vmstate_pcibus, bus); +} + static void pci_bus_class_init(ObjectClass *klass, void *data) { BusClass *k = BUS_CLASS(klass); @@ -68,6 +95,8 @@ static void pci_bus_class_init(ObjectClass *klass, void *data) k->print_dev = pcibus_dev_print; k->get_dev_path = pcibus_get_dev_path; k->get_fw_dev_path = pcibus_get_fw_dev_path; + k->realize = pci_bus_realize; + k->unrealize = pci_bus_unrealize; k->reset = pcibus_reset; } @@ -75,7 +104,6 @@ static const TypeInfo pci_bus_info = { .name = TYPE_PCI_BUS, .parent = TYPE_BUS, .instance_size = sizeof(PCIBus), - .instance_finalize = pci_bus_finalize, .class_init = pci_bus_class_init, }; @@ -95,17 +123,6 @@ static uint16_t pci_default_sub_device_id = PCI_SUBDEVICE_ID_QEMU; static QLIST_HEAD(, PCIHostState) pci_host_bridges; -static const VMStateDescription vmstate_pcibus = { - .name = "PCIBUS", - .version_id = 1, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT32_EQUAL(nirq, PCIBus), - VMSTATE_VARRAY_INT32(irq_count, PCIBus, nirq, 0, vmstate_info_int32, int32_t), - VMSTATE_END_OF_LIST() - } -}; static int pci_bar(PCIDevice *d, int reg) { uint8_t type; @@ -299,8 +316,6 @@ static void pci_bus_init(PCIBus *bus, DeviceState *parent, QLIST_INIT(&bus->child); pci_host_bus_register(bus, parent); - - vmstate_register(NULL, -1, &vmstate_pcibus, bus); } bool pci_bus_is_express(PCIBus *bus) @@ -369,12 +384,6 @@ int pci_bus_num(PCIBus *s) return s->parent_dev->config[PCI_SECONDARY_BUS]; } -static void pci_bus_finalize(Object *obj) -{ - PCIBus *bus = PCI_BUS(obj); - vmstate_unregister(NULL, &vmstate_pcibus, bus); -} - static int get_pci_config_device(QEMUFile *f, void *pv, size_t size) { PCIDevice *s = container_of(pv, PCIDevice, config); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index cea9469..3063109 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -510,7 +510,6 @@ static int spapr_phb_init(SysBusDevice *s) DeviceState *dev = DEVICE(s); sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); PCIHostState *phb = PCI_HOST_BRIDGE(s); - const char *busname; char *namebuf; int i; PCIBus *bus; @@ -594,26 +593,8 @@ static int spapr_phb_init(SysBusDevice *s) get_system_io(), 0, SPAPR_PCI_IO_WIN_SIZE); memory_region_add_subregion(get_system_memory(), sphb->io_win_addr, &sphb->iowindow); - /* - * Selecting a busname is more complex than you'd think, due to - * interacting constraints. If the user has specified an id - * explicitly for the phb , then we want to use the qdev default - * of naming the bus based on the bridge device (so the user can - * then assign devices to it in the way they expect). For the - * first / default PCI bus (index=0) we want to use just "pci" - * because libvirt expects there to be a bus called, simply, - * "pci". Otherwise, we use the same name as in the device tree, - * since it's unique by construction, and makes the guest visible - * BUID clear. - */ - if (dev->id) { - busname = NULL; - } else if (sphb->index == 0) { - busname = "pci"; - } else { - busname = sphb->dtbusname; - } - bus = pci_register_bus(dev, busname, + + bus = pci_register_bus(dev, NULL, pci_spapr_set_irq, pci_spapr_map_irq, sphb, &sphb->memspace, &sphb->iospace, PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index 1bb56c4..3273c8a 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -238,9 +238,10 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static int ssi_sd_init(SSISlave *dev) +static int ssi_sd_init(SSISlave *d) { - ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, dev); + DeviceState *dev = DEVICE(d); + ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); DriveInfo *dinfo; s->mode = SSI_SD_CMD; @@ -249,7 +250,7 @@ static int ssi_sd_init(SSISlave *dev) if (s->sd == NULL) { return -1; } - register_savevm(&dev->qdev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); + register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); return 0; } diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 2c25260..017f022 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -15,7 +15,7 @@ #include "hw/ssi.h" struct SSIBus { - BusState qbus; + BusState parent_obj; }; #define TYPE_SSI_BUS "SSI" @@ -60,7 +60,7 @@ static int ssi_slave_init(DeviceState *dev) if (ssc->transfer_raw == ssi_transfer_raw_default && ssc->cs_polarity != SSI_CS_NONE) { - qdev_init_gpio_in(&s->qdev, ssi_cs_default, 1); + qdev_init_gpio_in(dev, ssi_cs_default, 1); } return ssc->init(s); @@ -88,7 +88,7 @@ static const TypeInfo ssi_slave_info = { DeviceState *ssi_create_slave_no_init(SSIBus *bus, const char *name) { - return qdev_create(&bus->qbus, name); + return qdev_create(BUS(bus), name); } DeviceState *ssi_create_slave(SSIBus *bus, const char *name) @@ -108,11 +108,12 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name) uint32_t ssi_transfer(SSIBus *bus, uint32_t val) { + BusState *b = BUS(bus); BusChild *kid; SSISlaveClass *ssc; uint32_t r = 0; - QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) { + QTAILQ_FOREACH(kid, &b->children, sibling) { SSISlave *slave = SSI_SLAVE(kid->child); ssc = SSI_SLAVE_GET_CLASS(slave); r |= ssc->transfer_raw(slave, val); @@ -156,7 +157,7 @@ static int ssi_auto_connect_slave(Object *child, void *opaque) } cs_line = qdev_get_gpio_in(DEVICE(dev), 0); - qdev_set_parent_bus(DEVICE(dev), &arg->bus->qbus); + qdev_set_parent_bus(DEVICE(dev), BUS(arg->bus)); **arg->cs_linep = cs_line; (*arg->cs_linep)++; return 0; diff --git a/include/hw/boards.h b/include/hw/boards.h index c2096e6..6b17397 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -6,6 +6,7 @@ #include "sysemu/blockdev.h" #include "sysemu/qemumachine.h" #include "hw/qdev.h" +#include "qom/object.h" typedef struct QEMUMachineInitArgs { const QEMUMachine *machine; @@ -50,9 +51,59 @@ struct QEMUMachine { const char *hw_version; }; +#define TYPE_MACHINE_SUFFIX "-machine" int qemu_register_machine(QEMUMachine *m); -QEMUMachine *find_default_machine(void); -extern QEMUMachine *current_machine; +#define TYPE_MACHINE "machine" +#define MACHINE(obj) \ + OBJECT_CHECK(MachineState, (obj), TYPE_MACHINE) +#define MACHINE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(MachineClass, (obj), TYPE_MACHINE) +#define MACHINE_CLASS(klass) \ + OBJECT_CLASS_CHECK(MachineClass, (klass), TYPE_MACHINE) + +typedef struct MachineState MachineState; +typedef struct MachineClass MachineClass; + +MachineClass *find_default_machine(void); +extern MachineState *current_machine; + +/** + * MachineClass: + * @qemu_machine: #QEMUMachine + */ +struct MachineClass { + /*< private >*/ + ObjectClass parent_class; + /*< public >*/ + + QEMUMachine *qemu_machine; +}; + +/** + * MachineState: + */ +struct MachineState { + /*< private >*/ + Object parent_obj; + /*< public >*/ + + char *accel; + bool kernel_irqchip; + int kvm_shadow_mem; + char *kernel; + char *initrd; + char *append; + char *dtb; + char *dumpdtb; + int phandle_start; + char *dt_compatible; + bool dump_guest_core; + bool mem_merge; + bool usb; + char *firmware; + + QEMUMachineInitArgs init_args; +}; #endif diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 1ed0691..dbe473c 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -36,6 +36,8 @@ typedef int (*qdev_event)(DeviceState *dev); typedef void (*qdev_resetfn)(DeviceState *dev); typedef void (*DeviceRealize)(DeviceState *dev, Error **errp); typedef void (*DeviceUnrealize)(DeviceState *dev, Error **errp); +typedef void (*BusRealize)(BusState *bus, Error **errp); +typedef void (*BusUnrealize)(BusState *bus, Error **errp); struct VMStateDescription; @@ -174,6 +176,9 @@ struct BusClass { */ char *(*get_fw_dev_path)(DeviceState *dev); void (*reset)(BusState *bus); + BusRealize realize; + BusUnrealize unrealize; + /* maximum devices allowed on the bus, 0: no limit. */ int max_dev; /* number of automatically allocated bus ids (e.g. ide.0) */ @@ -199,6 +204,7 @@ struct BusState { int allow_hotplug; HotplugHandler *hotplug_handler; int max_index; + bool realized; QTAILQ_HEAD(ChildrenHead, BusChild) children; QLIST_ENTRY(BusState) sibling; }; diff --git a/include/hw/ssi.h b/include/hw/ssi.h index fdae317..6c13fb2 100644 --- a/include/hw/ssi.h +++ b/include/hw/ssi.h @@ -56,13 +56,12 @@ typedef struct SSISlaveClass { } SSISlaveClass; struct SSISlave { - DeviceState qdev; + DeviceState parent_obj; /* Chip select state */ bool cs; }; -#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev) #define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev) extern const VMStateDescription vmstate_ssi_slave; diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h index 1d2040b..4746312 100644 --- a/include/hw/virtio/virtio-serial.h +++ b/include/hw/virtio/virtio-serial.h @@ -81,15 +81,15 @@ typedef struct VirtIOSerialPortClass { bool is_console; /* - * The per-port (or per-app) init function that's called when a + * The per-port (or per-app) realize function that's called when a * new device is found on the bus. */ - int (*init)(VirtIOSerialPort *port); + DeviceRealize realize; /* - * Per-port exit function that's called when a port gets + * Per-port unrealize function that's called when a port gets * hot-unplugged or removed. */ - int (*exit)(VirtIOSerialPort *port); + DeviceUnrealize unrealize; /* Callbacks for guest events */ /* Guest opened/closed device. */ diff --git a/qdev-monitor.c b/qdev-monitor.c index 6673e3c..9268c87 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -522,7 +522,7 @@ DeviceState *qdev_device_add(QemuOpts *opts) return NULL; } - /* create device, set properties */ + /* create device */ dev = DEVICE(object_new(driver)); if (bus) { @@ -533,11 +533,7 @@ DeviceState *qdev_device_add(QemuOpts *opts) if (id) { dev->id = id; } - if (qemu_opt_foreach(opts, set_property, dev, 1) != 0) { - object_unparent(OBJECT(dev)); - object_unref(OBJECT(dev)); - return NULL; - } + if (dev->id) { object_property_add_child(qdev_get_peripheral(), dev->id, OBJECT(dev), NULL); @@ -549,6 +545,13 @@ DeviceState *qdev_device_add(QemuOpts *opts) g_free(name); } + /* set properties */ + if (qemu_opt_foreach(opts, set_property, dev, 1) != 0) { + object_unparent(OBJECT(dev)); + object_unref(OBJECT(dev)); + return NULL; + } + dev->opts = opts; object_property_set_bool(OBJECT(dev), true, "realized", &err); if (err != NULL) { @@ -114,8 +114,11 @@ void qmp_cpu(int64_t index, Error **errp) void qmp_cpu_add(int64_t id, Error **errp) { - if (current_machine->hot_add_cpu) { - current_machine->hot_add_cpu(id, errp); + MachineClass *mc; + + mc = MACHINE_GET_CLASS(current_machine); + if (mc->qemu_machine->hot_add_cpu) { + mc->qemu_machine->hot_add_cpu(id, errp); } else { error_setg(errp, "Not supported"); } diff --git a/qom/object.c b/qom/object.c index 660859c..c88909c 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1293,6 +1293,7 @@ void object_property_add_str(Object *obj, const char *name, void (*set)(Object *, const char *, Error **), Error **errp) { + Error *local_err = NULL; StringProperty *prop = g_malloc0(sizeof(*prop)); prop->get = get; @@ -1302,7 +1303,11 @@ void object_property_add_str(Object *obj, const char *name, get ? property_get_str : NULL, set ? property_set_str : NULL, property_release_str, - prop, errp); + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } } typedef struct BoolProperty @@ -1349,6 +1354,7 @@ void object_property_add_bool(Object *obj, const char *name, void (*set)(Object *, bool, Error **), Error **errp) { + Error *local_err = NULL; BoolProperty *prop = g_malloc0(sizeof(*prop)); prop->get = get; @@ -1358,7 +1364,11 @@ void object_property_add_bool(Object *obj, const char *name, get ? property_get_bool : NULL, set ? property_set_bool : NULL, property_release_bool, - prop, errp); + prop, &local_err); + if (local_err) { + error_propagate(errp, local_err); + g_free(prop); + } } static char *qdev_get_type(Object *obj, Error **errp) diff --git a/tests/Makefile b/tests/Makefile index e146f81..7bc3999 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -69,9 +69,24 @@ gcov-files-ipack-y += hw/ipack/ipack.c check-qtest-ipack-y += tests/ipoctal232-test$(EXESUF) gcov-files-ipack-y += hw/char/ipoctal232.c +check-qtest-virtioserial-y += tests/virtio-console-test$(EXESUF) +gcov-files-virtioserial-y += hw/char/virtio-console.c + gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio.c check-qtest-virtio-y += tests/virtio-net-test$(EXESUF) gcov-files-virtio-y += i386-softmmu/hw/net/virtio-net.c +check-qtest-virtio-y += tests/virtio-balloon-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/virtio/virtio-balloon.c +check-qtest-virtio-y += tests/virtio-blk-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/block/virtio-blk.c +check-qtest-virtio-y += tests/virtio-rng-test$(EXESUF) +gcov-files-virtio-y += hw/virtio/virtio-rng.c +check-qtest-virtio-y += tests/virtio-scsi-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/scsi/virtio-scsi.c +check-qtest-virtio-y += tests/virtio-serial-test$(EXESUF) +gcov-files-virtio-y += i386-softmmu/hw/char/virtio-serial-bus.c +check-qtest-virtio-y += $(check-qtest-virtioserial-y) +gcov-files-virtio-y += $(gcov-files-virtioserial-y) check-qtest-pci-y += tests/e1000-test$(EXESUF) gcov-files-pci-y += hw/net/e1000.c @@ -87,9 +102,9 @@ gcov-files-pci-y += hw/net/ne2000.c check-qtest-pci-y += $(check-qtest-virtio-y) gcov-files-pci-y += $(gcov-files-virtio-y) hw/virtio/virtio-pci.c check-qtest-pci-y += tests/tpci200-test$(EXESUF) -gcov-files-pci-y += hw/char/tpci200.c +gcov-files-pci-y += hw/ipack/tpci200.c check-qtest-pci-y += $(check-qtest-ipack-y) -gcov-files-pci-y += $(gcov-files-ipack-y) hw/ipack/tpci200.c +gcov-files-pci-y += $(gcov-files-ipack-y) check-qtest-i386-y = tests/endianness-test$(EXESUF) check-qtest-i386-y += tests/fdc-test$(EXESUF) @@ -129,6 +144,8 @@ check-qtest-arm-y = tests/tmp105-test$(EXESUF) gcov-files-arm-y += hw/misc/tmp105.c check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) +check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF) +gcov-files-ppc64-y += ppc64-softmmu/hw/ppc/spapr_pci.c check-qtest-microblazeel-y = $(check-qtest-microblaze-y) check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) @@ -225,6 +242,7 @@ libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o tests/rtc-test$(EXESUF): tests/rtc-test.o tests/m48t59-test$(EXESUF): tests/m48t59-test.o tests/endianness-test$(EXESUF): tests/endianness-test.o +tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o @@ -239,7 +257,13 @@ tests/pcnet-test$(EXESUF): tests/pcnet-test.o tests/eepro100-test$(EXESUF): tests/eepro100-test.o tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o tests/ne2000-test$(EXESUF): tests/ne2000-test.o +tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o +tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o +tests/virtio-rng-test$(EXESUF): tests/virtio-rng-test.o +tests/virtio-scsi-test$(EXESUF): tests/virtio-scsi-test.o +tests/virtio-serial-test$(EXESUF): tests/virtio-serial-test.o +tests/virtio-console-test$(EXESUF): tests/virtio-console-test.o tests/tpci200-test$(EXESUF): tests/tpci200-test.o tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o tests/qom-test$(EXESUF): tests/qom-test.o diff --git a/tests/libqtest.c b/tests/libqtest.c index b69dfca..2b90e4a 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -34,6 +34,7 @@ #include "qapi/qmp/json-parser.h" #define MAX_IRQ 256 +#define SOCKET_TIMEOUT 5 QTestState *global_qtest; @@ -78,12 +79,16 @@ static int socket_accept(int sock) struct sockaddr_un addr; socklen_t addrlen; int ret; + struct timeval timeout = { .tv_sec = SOCKET_TIMEOUT, + .tv_usec = 0 }; + + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, + sizeof(timeout)); addrlen = sizeof(addr); do { ret = accept(sock, (struct sockaddr *)&addr, &addrlen); } while (ret == -1 && errno == EINTR); - g_assert_no_errno(ret); close(sock); return ret; @@ -147,12 +152,16 @@ QTestState *qtest_init(const char *extra_args) } s->fd = socket_accept(sock); - s->qmp_fd = socket_accept(qmpsock); + if (s->fd >= 0) { + s->qmp_fd = socket_accept(qmpsock); + } unlink(socket_path); unlink(qmp_socket_path); g_free(socket_path); g_free(qmp_socket_path); + g_assert(s->fd >= 0 && s->qmp_fd >= 0); + s->rx = g_string_new(""); for (i = 0; i < MAX_IRQ; i++) { s->irq_level[i] = false; diff --git a/tests/qdev-monitor-test.c b/tests/qdev-monitor-test.c index ba7f9cc..e20ffd6 100644 --- a/tests/qdev-monitor-test.c +++ b/tests/qdev-monitor-test.c @@ -32,8 +32,7 @@ static void test_device_add(void) "}}"); g_assert(response); error = qdict_get_qdict(response, "error"); - g_assert(!strcmp(qdict_get_try_str(error, "desc") ?: "", - "Device needs media, but drive is empty")); + g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError"); QDECREF(response); /* Delete the drive */ @@ -42,7 +41,7 @@ static void test_device_add(void) " \"command-line\": \"drive_del drive0\"" "}}"); g_assert(response); - g_assert(!strcmp(qdict_get_try_str(response, "return") ?: "(null)", "")); + g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, ""); QDECREF(response); /* Try to re-add the drive. This fails with duplicate IDs if a leaked @@ -53,8 +52,7 @@ static void test_device_add(void) " \"command-line\": \"drive_add pci-addr=auto if=none,id=drive0\"" "}}"); g_assert(response); - g_assert(!strcmp(qdict_get_try_str(response, "return") ?: "", - "OK\r\n")); + g_assert_cmpstr(qdict_get_try_str(response, "return"), ==, "OK\r\n"); QDECREF(response); qtest_end(); diff --git a/tests/qom-test.c b/tests/qom-test.c index b6671fb..6d9a00b 100644 --- a/tests/qom-test.c +++ b/tests/qom-test.c @@ -10,6 +10,7 @@ #include <glib.h> #include <string.h> +#include "qemu-common.h" #include "libqtest.h" #include "qemu/osdep.h" #include "qapi/qmp/types.h" @@ -43,6 +44,40 @@ static bool is_blacklisted(const char *arch, const char *mach) return false; } +static void test_properties(const char *path) +{ + char *child_path; + QDict *response, *tuple; + QList *list; + QListEntry *entry; + + g_test_message("Obtaining properties of %s", path); + response = qmp("{ 'execute': 'qom-list'," + " 'arguments': { 'path': '%s' } }", path); + g_assert(response); + + g_assert(qdict_haskey(response, "return")); + list = qobject_to_qlist(qdict_get(response, "return")); + QLIST_FOREACH_ENTRY(list, entry) { + tuple = qobject_to_qdict(qlist_entry_obj(entry)); + if (strstart(qdict_get_str(tuple, "type"), "child<", NULL)) { + child_path = g_strdup_printf("%s/%s", + path, qdict_get_str(tuple, "name")); + test_properties(child_path); + g_free(child_path); + } else { + const char *prop = qdict_get_str(tuple, "name"); + g_test_message("Testing property %s.%s", path, prop); + response = qmp("{ 'execute': 'qom-get'," + " 'arguments': { 'path': '%s'," + " 'property': '%s' } }", + path, prop); + /* qom-get may fail but should not, e.g., segfault. */ + g_assert(response); + } + } +} + static void test_machine(gconstpointer data) { const char *machine = data; @@ -51,8 +86,12 @@ static void test_machine(gconstpointer data) args = g_strdup_printf("-machine %s", machine); qtest_start(args); + + test_properties("/machine"); + response = qmp("{ 'execute': 'quit' }"); g_assert(qdict_haskey(response, "return")); + qtest_end(); g_free(args); } diff --git a/tests/spapr-phb-test.c b/tests/spapr-phb-test.c new file mode 100644 index 0000000..b629de4 --- /dev/null +++ b/tests/spapr-phb-test.c @@ -0,0 +1,35 @@ +/* + * QTest testcase for SPAPR PHB + * + * Authors: + * Alexey Kardashevskiy <aik@ozlabs.ru> + * + * 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 <glib.h> + +#include "libqtest.h" + +#define TYPE_SPAPR_PCI_HOST_BRIDGE "spapr-pci-host-bridge" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void test_phb_device(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/spapr-phb/device", test_phb_device); + + qtest_start("-device " TYPE_SPAPR_PCI_HOST_BRIDGE ",index=100"); + + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-balloon-test.c b/tests/virtio-balloon-test.c new file mode 100644 index 0000000..becebb5 --- /dev/null +++ b/tests/virtio-balloon-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for VirtIO Balloon + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/balloon/pci/nop", pci_nop); + + qtest_start("-device virtio-balloon-pci"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c new file mode 100644 index 0000000..d53f875 --- /dev/null +++ b/tests/virtio-blk-test.c @@ -0,0 +1,34 @@ +/* + * QTest testcase for VirtIO Block Device + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/blk/pci/nop", pci_nop); + + qtest_start("-drive id=drv0,if=none,file=/dev/null " + "-device virtio-blk-pci,drive=drv0"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-console-test.c b/tests/virtio-console-test.c new file mode 100644 index 0000000..f98f5af2 --- /dev/null +++ b/tests/virtio-console-test.c @@ -0,0 +1,34 @@ +/* + * QTest testcase for VirtIO Console + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/console/pci/nop", pci_nop); + + qtest_start("-device virtio-serial-pci,id=vser0 " + "-device virtconsole,bus=vser0.0"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c new file mode 100644 index 0000000..402c206 --- /dev/null +++ b/tests/virtio-rng-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for VirtIO RNG + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/rng/pci/nop", pci_nop); + + qtest_start("-device virtio-rng-pci"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c new file mode 100644 index 0000000..3230908 --- /dev/null +++ b/tests/virtio-scsi-test.c @@ -0,0 +1,35 @@ +/* + * QTest testcase for VirtIO SCSI + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/scsi/pci/nop", pci_nop); + + qtest_start("-drive id=drv0,if=none,file=/dev/null " + "-device virtio-scsi-pci,id=vscsi0 " + "-device scsi-hd,bus=vscsi0.0,drive=drv0"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c new file mode 100644 index 0000000..e743875 --- /dev/null +++ b/tests/virtio-serial-test.c @@ -0,0 +1,33 @@ +/* + * QTest testcase for VirtIO Serial + * + * Copyright (c) 2014 SUSE LINUX Products GmbH + * + * 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 <glib.h> +#include <string.h> +#include "libqtest.h" +#include "qemu/osdep.h" + +/* Tests only initialization so far. TODO: Replace with functional tests */ +static void pci_nop(void) +{ +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + qtest_add_func("/virtio/serial/pci/nop", pci_nop); + + qtest_start("-device virtio-serial-pci"); + ret = g_test_run(); + + qtest_end(); + + return ret; +} @@ -1571,54 +1571,82 @@ void pcmcia_info(Monitor *mon, const QDict *qdict) /***********************************************************/ /* machine registration */ -static QEMUMachine *first_machine = NULL; -QEMUMachine *current_machine = NULL; +MachineState *current_machine; + +static void machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->qemu_machine = data; +} int qemu_register_machine(QEMUMachine *m) { - QEMUMachine **pm; - pm = &first_machine; - while (*pm != NULL) - pm = &(*pm)->next; - m->next = NULL; - *pm = m; + TypeInfo ti = { + .name = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL), + .parent = TYPE_MACHINE, + .class_init = machine_class_init, + .class_data = (void *)m, + }; + + type_register(&ti); + return 0; } -static QEMUMachine *find_machine(const char *name) +static MachineClass *find_machine(const char *name) { - QEMUMachine *m; + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); + MachineClass *mc = NULL; + + for (el = machines; el; el = el->next) { + MachineClass *temp = el->data; - for(m = first_machine; m != NULL; m = m->next) { - if (!strcmp(m->name, name)) - return m; - if (m->alias && !strcmp(m->alias, name)) - return m; + if (!strcmp(temp->qemu_machine->name, name)) { + mc = temp; + break; + } + if (temp->qemu_machine->alias && + !strcmp(temp->qemu_machine->alias, name)) { + mc = temp; + break; + } } - return NULL; + + g_slist_free(machines); + return mc; } -QEMUMachine *find_default_machine(void) +MachineClass *find_default_machine(void) { - QEMUMachine *m; + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); + MachineClass *mc = NULL; - for(m = first_machine; m != NULL; m = m->next) { - if (m->is_default) { - return m; + for (el = machines; el; el = el->next) { + MachineClass *temp = el->data; + + if (temp->qemu_machine->is_default) { + mc = temp; + break; } } - return NULL; + + g_slist_free(machines); + return mc; } MachineInfoList *qmp_query_machines(Error **errp) { + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); MachineInfoList *mach_list = NULL; QEMUMachine *m; - for (m = first_machine; m; m = m->next) { + for (el = machines; el; el = el->next) { + MachineClass *mc = el->data; MachineInfoList *entry; MachineInfo *info; + m = mc->qemu_machine; info = g_malloc0(sizeof(*info)); if (m->is_default) { info->has_is_default = true; @@ -1639,6 +1667,7 @@ MachineInfoList *qmp_query_machines(Error **errp) mach_list = entry; } + g_slist_free(machines); return mach_list; } @@ -1832,8 +1861,12 @@ void qemu_devices_reset(void) void qemu_system_reset(bool report) { - if (current_machine && current_machine->reset) { - current_machine->reset(); + MachineClass *mc; + + mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + + if (mc && mc->qemu_machine->reset) { + mc->qemu_machine->reset(); } else { qemu_devices_reset(); } @@ -2605,24 +2638,29 @@ static int debugcon_parse(const char *devname) return 0; } -static QEMUMachine *machine_parse(const char *name) +static MachineClass *machine_parse(const char *name) { - QEMUMachine *m, *machine = NULL; + MachineClass *mc = NULL; + GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); if (name) { - machine = find_machine(name); + mc = find_machine(name); } - if (machine) { - return machine; + if (mc) { + return mc; } printf("Supported machines are:\n"); - for (m = first_machine; m != NULL; m = m->next) { + for (el = machines; el; el = el->next) { + MachineClass *mc = el->data; + QEMUMachine *m = mc->qemu_machine; if (m->alias) { printf("%-20s %s (alias of %s)\n", m->alias, m->desc, m->name); } printf("%-20s %s%s\n", m->name, m->desc, m->is_default ? " (default)" : ""); } + + g_slist_free(machines); exit(!name || !is_help_option(name)); } @@ -2871,6 +2909,7 @@ int main(int argc, char **argv, char **envp) int optind; const char *optarg; const char *loadvm = NULL; + MachineClass *machine_class; QEMUMachine *machine; const char *cpu_model; const char *vga_model = "none"; @@ -2945,7 +2984,7 @@ int main(int argc, char **argv, char **envp) os_setup_early_signal_handling(); module_call_init(MODULE_INIT_MACHINE); - machine = find_default_machine(); + machine_class = find_default_machine(); cpu_model = NULL; ram_size = 0; snapshot = 0; @@ -3011,7 +3050,7 @@ int main(int argc, char **argv, char **envp) } switch(popt->index) { case QEMU_OPTION_M: - machine = machine_parse(optarg); + machine_class = machine_parse(optarg); break; case QEMU_OPTION_no_kvm_irqchip: { olist = qemu_find_opts("machine"); @@ -3567,7 +3606,7 @@ int main(int argc, char **argv, char **envp) } optarg = qemu_opt_get(opts, "type"); if (optarg) { - machine = machine_parse(optarg); + machine_class = machine_parse(optarg); } break; case QEMU_OPTION_no_kvm: @@ -3873,11 +3912,17 @@ int main(int argc, char **argv, char **envp) } #endif - if (machine == NULL) { + if (machine_class == NULL) { fprintf(stderr, "No machine found.\n"); exit(1); } + current_machine = MACHINE(object_new(object_class_get_name( + OBJECT_CLASS(machine_class)))); + object_property_add_child(object_get_root(), "machine", + OBJECT(current_machine), &error_abort); + + machine = machine_class->qemu_machine; if (machine->hw_version) { qemu_set_version(machine->hw_version); } @@ -4306,7 +4351,9 @@ int main(int argc, char **argv, char **envp) .kernel_cmdline = kernel_cmdline, .initrd_filename = initrd_filename, .cpu_model = cpu_model }; - machine->init(&args); + + current_machine->init_args = args; + machine->init(¤t_machine->init_args); audio_init(); @@ -4314,8 +4361,6 @@ int main(int argc, char **argv, char **envp) set_numa_modes(); - current_machine = machine; - /* init USB devices */ if (usb_enabled(false)) { if (foreach_device_config(DEV_USB, usb_parse) < 0) |