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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJTIPpQAAoJEPou0S0+fgE/waAQAImhHJ9NE9l9ba7xsuZRmr+B 8LvYDQ6VhiYG0sRQ+wn6GbU9yY91l+OgY2M/AaPRLSnqP84c5ypmRSq33777x19T Mvnh6kWwVHFTWTaLpeb7G6rb67fbinx79QOdiNd7QI/WKrEl14meMlIxqDtGH/tk e++GYQLzQbhkl13pNGfuqEu7Zwj1cvoPyZYiRmqRkONVoDuZg+3y0Joo9fYnl57p lAcw4SxKA9K/mdjZrDJRjpZ8pDuoMx3ILaKDhEscZGSi6/vSRHUHnfqYehWbCFl4 64V4QmAYuSHEiPjOdHxMaeAUgk5RYgvMTjsu7uDCCbrI1np5j0ELzjrU/X9BGiTP X1vYgCXRLmC9yNr4Bs4heIzdvEs7bw4XbM2IQ3ox102q1ZuYnS8BtGTr5G1nS/VE p7gdQ9tbfBnuZYE5ahI/nVM853xKWYkgQvYEbFKyCjTtPCN2c/2cbCpptBFUBhHN Ud6N3i3x39BuwDRIWXiFmrHEOa4jOcoorTVWmJyoXbE7NLp4cDZPTXEzU3R6aB4v KtzFcJAUUQsbXRJCllVieVjfDyuL3WdUdIpLTnXsgcr+495FKVeZI+98Jxi8ncVv s8J/OnXoZgE9Uwq9kZFRHTA7knsfxcFtAjTkbT8P/cLLK03o+c95d1m0OeXAl+FM RdFERQ0NZP8dRuOTQ3Fn =2uZO -----END PGP SIGNATURE----- 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>
This commit is contained in:
		
						commit
						c8d146aecc
					
				| @ -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; | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										28
									
								
								hw/core/machine.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								hw/core/machine.c
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||
| @ -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) | ||||
|  | ||||
| @ -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 */ | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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 max111x_class_init(ObjectClass *klass, void *data) | ||||
| { | ||||
|     SSISlaveClass *k = SSI_SLAVE_CLASS(klass); | ||||
| 
 | ||||
|     k->transfer = max111x_transfer; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
|     k->transfer = max111x_transfer; | ||||
| } | ||||
| 
 | ||||
| static const TypeInfo max1110_info = { | ||||
|     .name          = "max1110", | ||||
|     .parent        = TYPE_SSI_SLAVE, | ||||
|     .instance_size = sizeof(MAX111xState), | ||||
|     .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); | ||||
| } | ||||
|  | ||||
							
								
								
									
										51
									
								
								hw/pci/pci.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										11
									
								
								hw/ssi/ssi.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								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; | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
| }; | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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. */ | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
							
								
								
									
										7
									
								
								qmp.c
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								qmp.c
									
									
									
									
									
								
							| @ -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"); | ||||
|     } | ||||
|  | ||||
							
								
								
									
										14
									
								
								qom/object.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								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) | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
							
								
								
									
										35
									
								
								tests/spapr-phb-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								tests/spapr-phb-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										33
									
								
								tests/virtio-balloon-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/virtio-balloon-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										34
									
								
								tests/virtio-blk-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tests/virtio-blk-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										34
									
								
								tests/virtio-console-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								tests/virtio-console-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										33
									
								
								tests/virtio-rng-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/virtio-rng-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										35
									
								
								tests/virtio-scsi-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								tests/virtio-scsi-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										33
									
								
								tests/virtio-serial-test.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								tests/virtio-serial-test.c
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| } | ||||
							
								
								
									
										129
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								vl.c
									
									
									
									
									
								
							| @ -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(m = first_machine; m != NULL; m = m->next) { | ||||
|         if (!strcmp(m->name, name)) | ||||
|             return m; | ||||
|         if (m->alias && !strcmp(m->alias, name)) | ||||
|             return m; | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|     for (el = machines; el; el = el->next) { | ||||
|         MachineClass *temp = el->data; | ||||
| 
 | ||||
| QEMUMachine *find_default_machine(void) | ||||
| { | ||||
|     QEMUMachine *m; | ||||
| 
 | ||||
|     for(m = first_machine; m != NULL; m = m->next) { | ||||
|         if (m->is_default) { | ||||
|             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; | ||||
| } | ||||
| 
 | ||||
| MachineClass *find_default_machine(void) | ||||
| { | ||||
|     GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); | ||||
|     MachineClass *mc = NULL; | ||||
| 
 | ||||
|     for (el = machines; el; el = el->next) { | ||||
|         MachineClass *temp = el->data; | ||||
| 
 | ||||
|         if (temp->qemu_machine->is_default) { | ||||
|             mc = temp; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Peter Maydell
						Peter Maydell