diff options
200 files changed, 2204 insertions, 516 deletions
@@ -4502,7 +4502,7 @@ if [ "$dtc_internal" = "yes" ]; then fi # build tree in object directory in case the source is not in the current directory -DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos" +DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema" DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS qapi-generated" diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 35e2af4..de6f0fe 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -149,6 +149,7 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->props = virtio_9p_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = virtio_9p_device_init; vdc->get_features = virtio_9p_get_features; vdc->get_config = virtio_9p_get_config; diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 365b2f1..01b4dfb 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -1420,6 +1420,7 @@ static void ac97_class_init (ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5; k->revision = 0x01; k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Intel 82801AA AC97 Audio"; dc->vmsd = &vmstate_ac97; dc->props = ac97_properties; diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index f72e6ee..0421d47 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -364,6 +364,7 @@ static void adlib_class_initfn (ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS (klass); dc->realize = adlib_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = ADLIB_DESC; dc->props = adlib_properties; } diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 7365c3c..666096b 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -685,6 +685,7 @@ static void cs4231a_class_initfn (ObjectClass *klass, void *data) dc->realize = cs4231a_realizefn; dc->reset = cs4231a_reset; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Crystal Semiconductor CS4231A"; dc->vmsd = &vmstate_cs4231a; dc->props = cs4231a_properties; diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index f2c40da..adb66ce 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -1069,6 +1069,7 @@ static void es1370_class_init (ObjectClass *klass, void *data) k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; k->subsystem_vendor_id = 0x4942; k->subsystem_id = 0x4c4c; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "ENSONIQ AudioPCI ES1370"; dc->vmsd = &vmstate_es1370; } diff --git a/hw/audio/gus.c b/hw/audio/gus.c index f45ed0b..71be3c6 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -315,6 +315,7 @@ static void gus_class_initfn (ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS (klass); dc->realize = gus_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Gravis Ultrasound GF1"; dc->vmsd = &vmstate_gus; dc->props = gus_properties; diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index 362d8c0..9550c97 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -1034,6 +1034,7 @@ static void hda_audio_output_class_init(ObjectClass *klass, void *data) k->exit = hda_audio_exit; k->command = hda_audio_command; k->stream = hda_audio_stream; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, output-only (line-out)"; dc->vmsd = &vmstate_hda_audio; dc->props = hda_audio_properties; @@ -1055,6 +1056,7 @@ static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) k->exit = hda_audio_exit; k->command = hda_audio_command; k->stream = hda_audio_stream; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, duplex (line-out, line-in)"; dc->vmsd = &vmstate_hda_audio; dc->props = hda_audio_properties; @@ -1076,6 +1078,7 @@ static void hda_audio_micro_class_init(ObjectClass *klass, void *data) k->exit = hda_audio_exit; k->command = hda_audio_command; k->stream = hda_audio_stream; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "HDA Audio Codec, duplex (speaker, microphone)"; dc->vmsd = &vmstate_hda_audio; dc->props = hda_audio_properties; diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 58984dc..32e44ad 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -1258,6 +1258,7 @@ static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) k->device_id = 0x2668; k->revision = 1; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Intel HD Audio Controller (ich6)"; } @@ -1268,6 +1269,7 @@ static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) k->device_id = 0x293e; k->revision = 3; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Intel HD Audio Controller (ich9)"; } @@ -1296,6 +1298,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data) DeviceClass *k = DEVICE_CLASS(klass); k->init = hda_codec_dev_init; k->exit = hda_codec_dev_exit; + set_bit(DEVICE_CATEGORY_SOUND, k->categories); k->bus_type = TYPE_HDA_BUS; k->props = hda_props; } diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 7ad59a1..9004ce3 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -191,6 +191,7 @@ static void pcspk_class_initfn(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = pcspk_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->no_user = 1; dc->props = pcspk_properties; } diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c index 7d331b9..b66d6d2 100644 --- a/hw/audio/pl041.c +++ b/hw/audio/pl041.c @@ -626,6 +626,7 @@ static void pl041_device_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = pl041_init; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->no_user = 1; dc->reset = pl041_device_reset; dc->vmsd = &vmstate_pl041; diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index e697bc1..3e58688 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -1412,6 +1412,7 @@ static void sb16_class_initfn (ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS (klass); dc->realize = sb16_realizefn; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "Creative Sound Blaster 16"; dc->vmsd = &vmstate_sb16; dc->props = sb16_properties; diff --git a/hw/block/fdc.c b/hw/block/fdc.c index d32f6ba..50a350f 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -2249,6 +2249,7 @@ static void isabus_fdc_class_init(ObjectClass *klass, void *data) dc->reset = fdctrl_external_reset_isa; dc->vmsd = &vmstate_isa_fdc; dc->props = isa_fdc_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo isa_fdc_info = { @@ -2282,6 +2283,7 @@ static void sysbus_fdc_class_init(ObjectClass *klass, void *data) dc->reset = fdctrl_external_reset_sysbus; dc->vmsd = &vmstate_sysbus_fdc; dc->props = sysbus_fdc_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sysbus_fdc_info = { @@ -2305,6 +2307,7 @@ static void sun4m_fdc_class_init(ObjectClass *klass, void *data) dc->reset = fdctrl_external_reset_sysbus; dc->vmsd = &vmstate_sysbus_fdc; dc->props = sun4m_fdc_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sun4m_fdc_info = { diff --git a/hw/block/nvme.c b/hw/block/nvme.c index f15f04a..0263e5c 100644 --- a/hw/block/nvme.c +++ b/hw/block/nvme.c @@ -866,6 +866,7 @@ static void nvme_class_init(ObjectClass *oc, void *data) pc->revision = 1; pc->is_express = 1; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "Non-Volatile Memory Express"; dc->props = nvme_props; dc->vmsd = &nvme_vmstate; diff --git a/hw/block/pc_sysfw.c b/hw/block/pc_sysfw.c index 0669410..7db68f0 100644 --- a/hw/block/pc_sysfw.c +++ b/hw/block/pc_sysfw.c @@ -286,6 +286,7 @@ static void pcsysfw_class_init (ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS (klass); + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "PC System Firmware"; dc->init = pcsysfw_init; dc->props = pcsysfw_properties; diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index 2973859..825011d 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -723,6 +723,7 @@ static void pflash_cfi01_class_init(ObjectClass *klass, void *data) dc->realize = pflash_cfi01_realize; dc->props = pflash_cfi01_properties; dc->vmsd = &vmstate_pflash; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index cf12469..a786233 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -704,6 +704,7 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_blk_device_exit; dc->props = virtio_blk_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = virtio_blk_device_init; vdc->get_config = virtio_blk_update_config; vdc->set_config = virtio_blk_set_config; diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c index 03db12f..02d0d57 100644 --- a/hw/char/debugcon.c +++ b/hw/char/debugcon.c @@ -122,6 +122,7 @@ static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) dc->realize = debugcon_isa_realizefn; dc->props = debugcon_isa_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo debugcon_isa_info = { diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 69b9ed2..5c17eaa 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -449,6 +449,7 @@ static void imx_serial_class_init(ObjectClass *klass, void *data) k->init = imx_serial_init; dc->vmsd = &vmstate_imx_serial; dc->reset = imx_serial_reset_at_boot; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "i.MX series UART"; dc->props = imx32_serial_properties; } diff --git a/hw/char/ipack.c b/hw/char/ipack.c index e15540d..f890471 100644 --- a/hw/char/ipack.c +++ b/hw/char/ipack.c @@ -74,6 +74,7 @@ static Property ipack_device_props[] = { static void ipack_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_INPUT, k->categories); k->bus_type = TYPE_IPACK_BUS; k->init = ipack_device_dev_init; k->exit = ipack_device_dev_exit; diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c index c9698a6..88e2cca 100644 --- a/hw/char/ipoctal232.c +++ b/hw/char/ipoctal232.c @@ -585,6 +585,7 @@ static void ipoctal_class_init(ObjectClass *klass, void *data) ic->mem_read8 = mem_read8; ic->mem_write8 = mem_write8; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "GE IP-Octal 232 8-channel RS-232 IndustryPack"; dc->props = ipoctal_properties; dc->vmsd = &vmstate_ipoctal; diff --git a/hw/char/parallel.c b/hw/char/parallel.c index ad96ea5..7a3b264 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -607,6 +607,7 @@ static void parallel_isa_class_initfn(ObjectClass *klass, void *data) dc->realize = parallel_isa_realizefn; dc->props = parallel_isa_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo parallel_isa_info = { diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index cea8212..5cb77b3 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -102,6 +102,7 @@ static void serial_isa_class_initfn(ObjectClass *klass, void *data) dc->realize = serial_isa_realizefn; dc->vmsd = &vmstate_isa_serial; dc->props = serial_isa_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo serial_isa_info = { diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index a17c702..aec6705 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -205,6 +205,7 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data) pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_serial; dc->props = serial_pci_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) @@ -219,6 +220,7 @@ static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_multi_serial; dc->props = multi_2x_serial_pci_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) @@ -233,6 +235,7 @@ static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_multi_serial; dc->props = multi_4x_serial_pci_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo serial_pci_info = { diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 2993848..a799721 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -142,6 +142,21 @@ static Property spapr_vty_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_vty = { + .name = "spapr_vty", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVTYDevice), + + VMSTATE_UINT32(in, VIOsPAPRVTYDevice), + VMSTATE_UINT32(out, VIOsPAPRVTYDevice), + VMSTATE_BUFFER(buf, VIOsPAPRVTYDevice), + VMSTATE_END_OF_LIST() + }, +}; + static void spapr_vty_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -152,6 +167,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data) k->dt_type = "serial"; k->dt_compatible = "hvterm1"; dc->props = spapr_vty_properties; + dc->vmsd = &vmstate_spapr_vty; } static const TypeInfo spapr_vty_info = { diff --git a/hw/char/tpci200.c b/hw/char/tpci200.c index a199e57..d9e17b2 100644 --- a/hw/char/tpci200.c +++ b/hw/char/tpci200.c @@ -652,6 +652,7 @@ static void tpci200_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_BRIDGE_OTHER; k->subsystem_vendor_id = PCI_VENDOR_ID_TEWS; k->subsystem_id = 0x300A; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "TEWS TPCI200 IndustryPack carrier"; dc->vmsd = &vmstate_tpci200; } diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index cc3d1dd..da417c7 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -971,6 +971,7 @@ 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->unplug = qdev_simple_unplug_cb; @@ -1017,6 +1018,7 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_serial_device_exit; dc->props = virtio_serial_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); vdc->init = virtio_serial_device_init; vdc->get_features = get_features; vdc->get_config = get_config; diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 3a324fb..6e1ed1e 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -74,13 +74,14 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) } } -static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) +static int prop_print_bit(DeviceState *dev, Property *prop, char *dest, + size_t len) { uint32_t *p = qdev_get_prop_ptr(dev, prop); return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); } -static void get_bit(Object *obj, Visitor *v, void *opaque, +static void prop_get_bit(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); @@ -91,7 +92,7 @@ static void get_bit(Object *obj, Visitor *v, void *opaque, visit_type_bool(v, &value, name, errp); } -static void set_bit(Object *obj, Visitor *v, void *opaque, +static void prop_set_bit(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { DeviceState *dev = DEVICE(obj); @@ -115,9 +116,9 @@ static void set_bit(Object *obj, Visitor *v, void *opaque, PropertyInfo qdev_prop_bit = { .name = "boolean", .legacy_name = "on/off", - .print = print_bit, - .get = get_bit, - .set = set_bit, + .print = prop_print_bit, + .get = prop_get_bit, + .set = prop_set_bit, }; /* --- bool --- */ diff --git a/hw/cpu/icc_bus.c b/hw/cpu/icc_bus.c index 8788144..8748cc5 100644 --- a/hw/cpu/icc_bus.c +++ b/hw/cpu/icc_bus.c @@ -101,11 +101,19 @@ static void icc_bridge_init(Object *obj) s->icc_bus.apic_address_space = &s->apic_container; } +static void icc_bridge_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); +} + static const TypeInfo icc_bridge_info = { .name = TYPE_ICC_BRIDGE, .parent = TYPE_SYS_BUS_DEVICE, .instance_init = icc_bridge_init, .instance_size = sizeof(ICCBridgeState), + .class_init = icc_bridge_class_init, }; diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index a440575..dbd1f4a 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2937,6 +2937,7 @@ static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_cirrus_vga; dc->realize = isa_cirrus_vga_realizefn; dc->props = isa_cirrus_vga_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo isa_cirrus_vga_info = { @@ -3002,6 +3003,7 @@ static void cirrus_vga_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_CIRRUS; k->device_id = CIRRUS_ID_CLGD5446; k->class_id = PCI_CLASS_DISPLAY_VGA; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "Cirrus CLGD 54xx VGA"; dc->vmsd = &vmstate_pci_cirrus_vga; dc->props = pci_vga_cirrus_properties; diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index 79a0a50..2d3e912 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -528,6 +528,7 @@ static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = g364fb_sysbus_init; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "G364 framebuffer"; dc->reset = g364fb_sysbus_reset; dc->vmsd = &vmstate_g364fb; diff --git a/hw/display/pl110.c b/hw/display/pl110.c index 60afcf3..31993a7 100644 --- a/hw/display/pl110.c +++ b/hw/display/pl110.c @@ -481,6 +481,7 @@ static void pl110_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = pl110_init; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->no_user = 1; dc->vmsd = &vmstate_pl110; } @@ -498,6 +499,7 @@ static void pl110_versatile_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = pl110_versatile_init; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->no_user = 1; dc->vmsd = &vmstate_pl110; } @@ -515,6 +517,7 @@ static void pl111_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = pl111_init; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->no_user = 1; dc->vmsd = &vmstate_pl110; } diff --git a/hw/display/qxl.c b/hw/display/qxl.c index ddefa06..c537057 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2323,6 +2323,7 @@ static void qxl_primary_class_init(ObjectClass *klass, void *data) k->vendor_id = REDHAT_PCI_VENDOR_ID; k->device_id = QXL_DEVICE_ID_STABLE; k->class_id = PCI_CLASS_DISPLAY_VGA; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "Spice QXL GPU (primary, vga compatible)"; dc->reset = qxl_reset_handler; dc->vmsd = &qxl_vmstate; @@ -2345,6 +2346,7 @@ static void qxl_secondary_class_init(ObjectClass *klass, void *data) k->vendor_id = REDHAT_PCI_VENDOR_ID; k->device_id = QXL_DEVICE_ID_STABLE; k->class_id = PCI_CLASS_DISPLAY_OTHER; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->desc = "Spice QXL GPU (secondary)"; dc->reset = qxl_reset_handler; dc->vmsd = &qxl_vmstate; diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 8d560ec..c2a19ad 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -87,6 +87,7 @@ static void vga_isa_class_initfn(ObjectClass *klass, void *data) dc->reset = vga_isa_reset; dc->vmsd = &vmstate_vga_common; dc->props = vga_isa_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo vga_isa_info = { diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index 3e150ab..b3a45c8 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -198,6 +198,7 @@ static void vga_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_DISPLAY_VGA; dc->vmsd = &vmstate_vga_pci; dc->props = vga_pci_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo vga_info = { diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 3536cde..a6a8cdc 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1306,6 +1306,7 @@ static void vmsvga_class_init(ObjectClass *klass, void *data) dc->reset = vmsvga_reset; dc->vmsd = &vmstate_vmware_vga; dc->props = vga_vmware_properties; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); } static const TypeInfo vmsvga_info = { diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index 5f8b972..853d455 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -227,6 +227,7 @@ static void gpio_i2c_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = gpio_i2c_init; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "Virtual GPIO to I2C bridge"; } diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 22ef3b9..c97e7f7 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -224,6 +224,7 @@ static void i2c_slave_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = i2c_slave_qdev_init; + set_bit(DEVICE_CATEGORY_MISC, k->categories); k->bus_type = TYPE_I2C_BUS; k->props = i2c_props; } diff --git a/hw/i386/kvm/pci-assign.c b/hw/i386/kvm/pci-assign.c index ff33dc8..5618173 100644 --- a/hw/i386/kvm/pci-assign.c +++ b/hw/i386/kvm/pci-assign.c @@ -1856,6 +1856,7 @@ static void assign_class_init(ObjectClass *klass, void *data) dc->props = assigned_dev_properties; dc->vmsd = &vmstate_assigned_device; dc->reset = reset_assigned_device; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "KVM-based PCI passthrough"; } diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 419adde..bba150f 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -1338,6 +1338,7 @@ static void sysbus_ahci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_sysbus_ahci; dc->props = sysbus_ahci_properties; dc->reset = sysbus_ahci_reset; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sysbus_ahci_info = { diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 4eb5488..bff952b 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -160,6 +160,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_STORAGE_SATA; dc->vmsd = &vmstate_ich9_ahci; dc->reset = pci_ich9_reset; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo ich_ahci_info = { diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 7243c82..bbc8c6b 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -118,6 +118,7 @@ static void isa_ide_class_initfn(ObjectClass *klass, void *data) dc->fw_name = "ide"; dc->reset = isa_ide_reset; dc->props = isa_ide_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo isa_ide_info = { diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 58532fe..56cf00e 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -248,6 +248,7 @@ static void piix3_ide_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; } @@ -267,6 +268,7 @@ static void piix3_ide_xen_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; dc->unplug = pci_piix3_xen_ide_unplug; } @@ -289,6 +291,7 @@ static void piix4_ide_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82371AB; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; } diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c index 6a272b0..1d84e15 100644 --- a/hw/ide/qdev.c +++ b/hw/ide/qdev.c @@ -282,6 +282,7 @@ static void ide_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->init = ide_qdev_init; + set_bit(DEVICE_CATEGORY_STORAGE, k->categories); k->bus_type = TYPE_IDE_BUS; k->props = ide_props; } diff --git a/hw/ide/via.c b/hw/ide/via.c index 5a83191..d324884 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -223,6 +223,7 @@ static void via_ide_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIA_IDE; k->revision = 0x06; k->class_id = PCI_CLASS_STORAGE_IDE; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->no_user = 1; } diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 091912e..6b3c071 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -34,34 +34,19 @@ * ICP: Presentation layer */ -struct icp_server_state { - uint32_t xirr; - uint8_t pending_priority; - uint8_t mfrr; - qemu_irq output; -}; - #define XISR_MASK 0x00ffffff #define CPPR_MASK 0xff000000 #define XISR(ss) (((ss)->xirr) & XISR_MASK) #define CPPR(ss) (((ss)->xirr) >> 24) -struct ics_state; - -struct icp_state { - long nr_servers; - struct icp_server_state *ss; - struct ics_state *ics; -}; - -static void ics_reject(struct ics_state *ics, int nr); -static void ics_resend(struct ics_state *ics); -static void ics_eoi(struct ics_state *ics, int nr); +static void ics_reject(ICSState *ics, int nr); +static void ics_resend(ICSState *ics); +static void ics_eoi(ICSState *ics, int nr); -static void icp_check_ipi(struct icp_state *icp, int server) +static void icp_check_ipi(XICSState *icp, int server) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) { return; @@ -78,9 +63,9 @@ static void icp_check_ipi(struct icp_state *icp, int server) qemu_irq_raise(ss->output); } -static void icp_resend(struct icp_state *icp, int server) +static void icp_resend(XICSState *icp, int server) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; if (ss->mfrr < CPPR(ss)) { icp_check_ipi(icp, server); @@ -88,9 +73,9 @@ static void icp_resend(struct icp_state *icp, int server) ics_resend(icp->ics); } -static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) +static void icp_set_cppr(XICSState *icp, int server, uint8_t cppr) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; uint8_t old_cppr; uint32_t old_xisr; @@ -112,9 +97,9 @@ static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) } } -static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr) +static void icp_set_mfrr(XICSState *icp, int server, uint8_t mfrr) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; ss->mfrr = mfrr; if (mfrr < CPPR(ss)) { @@ -122,7 +107,7 @@ static void icp_set_mfrr(struct icp_state *icp, int server, uint8_t mfrr) } } -static uint32_t icp_accept(struct icp_server_state *ss) +static uint32_t icp_accept(ICPState *ss) { uint32_t xirr = ss->xirr; @@ -135,9 +120,9 @@ static uint32_t icp_accept(struct icp_server_state *ss) return xirr; } -static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) +static void icp_eoi(XICSState *icp, int server, uint32_t xirr) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; /* Send EOI -> ICS */ ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK); @@ -148,9 +133,9 @@ static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr) } } -static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) +static void icp_irq(XICSState *icp, int server, int nr, uint8_t priority) { - struct icp_server_state *ss = icp->ss + server; + ICPState *ss = icp->ss + server; trace_xics_icp_irq(server, nr, priority); @@ -168,39 +153,59 @@ static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority) } } -/* - * ICS: Source layer - */ - -struct ics_irq_state { - int server; - uint8_t priority; - uint8_t saved_priority; -#define XICS_STATUS_ASSERTED 0x1 -#define XICS_STATUS_SENT 0x2 -#define XICS_STATUS_REJECTED 0x4 -#define XICS_STATUS_MASKED_PENDING 0x8 - uint8_t status; +static const VMStateDescription vmstate_icp_server = { + .name = "icp/server", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32(xirr, ICPState), + VMSTATE_UINT8(pending_priority, ICPState), + VMSTATE_UINT8(mfrr, ICPState), + VMSTATE_END_OF_LIST() + }, }; -struct ics_state { - int nr_irqs; - int offset; - qemu_irq *qirqs; - bool *islsi; - struct ics_irq_state *irqs; - struct icp_state *icp; +static void icp_reset(DeviceState *dev) +{ + ICPState *icp = ICP(dev); + + icp->xirr = 0; + icp->pending_priority = 0xff; + icp->mfrr = 0xff; + + /* Make all outputs are deasserted */ + qemu_set_irq(icp->output, 0); +} + +static void icp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = icp_reset; + dc->vmsd = &vmstate_icp_server; +} + +static TypeInfo icp_info = { + .name = TYPE_ICP, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ICPState), + .class_init = icp_class_init, }; -static int ics_valid_irq(struct ics_state *ics, uint32_t nr) +/* + * ICS: Source layer + */ +static int ics_valid_irq(ICSState *ics, uint32_t nr) { return (nr >= ics->offset) && (nr < (ics->offset + ics->nr_irqs)); } -static void resend_msi(struct ics_state *ics, int srcno) +static void resend_msi(ICSState *ics, int srcno) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; /* FIXME: filter by server#? */ if (irq->status & XICS_STATUS_REJECTED) { @@ -212,9 +217,9 @@ static void resend_msi(struct ics_state *ics, int srcno) } } -static void resend_lsi(struct ics_state *ics, int srcno) +static void resend_lsi(ICSState *ics, int srcno) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; if ((irq->priority != 0xff) && (irq->status & XICS_STATUS_ASSERTED) @@ -224,9 +229,9 @@ static void resend_lsi(struct ics_state *ics, int srcno) } } -static void set_irq_msi(struct ics_state *ics, int srcno, int val) +static void set_irq_msi(ICSState *ics, int srcno, int val) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; trace_xics_set_irq_msi(srcno, srcno + ics->offset); @@ -240,9 +245,9 @@ static void set_irq_msi(struct ics_state *ics, int srcno, int val) } } -static void set_irq_lsi(struct ics_state *ics, int srcno, int val) +static void set_irq_lsi(ICSState *ics, int srcno, int val) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; trace_xics_set_irq_lsi(srcno, srcno + ics->offset); if (val) { @@ -255,7 +260,7 @@ static void set_irq_lsi(struct ics_state *ics, int srcno, int val) static void ics_set_irq(void *opaque, int srcno, int val) { - struct ics_state *ics = (struct ics_state *)opaque; + ICSState *ics = (ICSState *)opaque; if (ics->islsi[srcno]) { set_irq_lsi(ics, srcno, val); @@ -264,9 +269,9 @@ static void ics_set_irq(void *opaque, int srcno, int val) } } -static void write_xive_msi(struct ics_state *ics, int srcno) +static void write_xive_msi(ICSState *ics, int srcno) { - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; if (!(irq->status & XICS_STATUS_MASKED_PENDING) || (irq->priority == 0xff)) { @@ -277,16 +282,16 @@ static void write_xive_msi(struct ics_state *ics, int srcno) icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority); } -static void write_xive_lsi(struct ics_state *ics, int srcno) +static void write_xive_lsi(ICSState *ics, int srcno) { resend_lsi(ics, srcno); } -static void ics_write_xive(struct ics_state *ics, int nr, int server, +static void ics_write_xive(ICSState *ics, int nr, int server, uint8_t priority, uint8_t saved_priority) { int srcno = nr - ics->offset; - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; irq->server = server; irq->priority = priority; @@ -301,16 +306,16 @@ static void ics_write_xive(struct ics_state *ics, int nr, int server, } } -static void ics_reject(struct ics_state *ics, int nr) +static void ics_reject(ICSState *ics, int nr) { - struct ics_irq_state *irq = ics->irqs + nr - ics->offset; + ICSIRQState *irq = ics->irqs + nr - ics->offset; trace_xics_ics_reject(nr, nr - ics->offset); irq->status |= XICS_STATUS_REJECTED; /* Irrelevant but harmless for LSI */ irq->status &= ~XICS_STATUS_SENT; /* Irrelevant but harmless for MSI */ } -static void ics_resend(struct ics_state *ics) +static void ics_resend(ICSState *ics) { int i; @@ -324,10 +329,10 @@ static void ics_resend(struct ics_state *ics) } } -static void ics_eoi(struct ics_state *ics, int nr) +static void ics_eoi(ICSState *ics, int nr) { int srcno = nr - ics->offset; - struct ics_irq_state *irq = ics->irqs + srcno; + ICSIRQState *irq = ics->irqs + srcno; trace_xics_ics_eoi(nr); @@ -336,11 +341,92 @@ static void ics_eoi(struct ics_state *ics, int nr) } } +static void ics_reset(DeviceState *dev) +{ + ICSState *ics = ICS(dev); + int i; + + memset(ics->irqs, 0, sizeof(ICSIRQState) * ics->nr_irqs); + for (i = 0; i < ics->nr_irqs; i++) { + ics->irqs[i].priority = 0xff; + ics->irqs[i].saved_priority = 0xff; + } +} + +static int ics_post_load(void *opaque, int version_id) +{ + int i; + ICSState *ics = opaque; + + for (i = 0; i < ics->icp->nr_servers; i++) { + icp_resend(ics->icp, i); + } + + return 0; +} + +static const VMStateDescription vmstate_ics_irq = { + .name = "ics/irq", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(server, ICSIRQState), + VMSTATE_UINT8(priority, ICSIRQState), + VMSTATE_UINT8(saved_priority, ICSIRQState), + VMSTATE_UINT8(status, ICSIRQState), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_ics = { + .name = "ics", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .post_load = ics_post_load, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32_EQUAL(nr_irqs, ICSState), + + VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, + vmstate_ics_irq, ICSIRQState), + VMSTATE_END_OF_LIST() + }, +}; + +static int ics_realize(DeviceState *dev) +{ + ICSState *ics = ICS(dev); + + ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); + ics->islsi = g_malloc0(ics->nr_irqs * sizeof(bool)); + ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs); + + return 0; +} + +static void ics_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->init = ics_realize; + dc->vmsd = &vmstate_ics; + dc->reset = ics_reset; +} + +static TypeInfo ics_info = { + .name = TYPE_ICS, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ICSState), + .class_init = ics_class_init, +}; + /* * Exported functions */ -qemu_irq xics_get_qirq(struct icp_state *icp, int irq) +qemu_irq xics_get_qirq(XICSState *icp, int irq) { if (!ics_valid_irq(icp->ics, irq)) { return NULL; @@ -349,13 +435,17 @@ qemu_irq xics_get_qirq(struct icp_state *icp, int irq) return icp->ics->qirqs[irq - icp->ics->offset]; } -void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi) +void xics_set_irq_type(XICSState *icp, int irq, bool lsi) { assert(ics_valid_irq(icp->ics, irq)); icp->ics->islsi[irq - icp->ics->offset] = lsi; } +/* + * Guest interfaces + */ + static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong opcode, target_ulong *args) { @@ -405,7 +495,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr, server, priority; if ((nargs != 3) || (nret != 1)) { @@ -433,7 +523,7 @@ static void rtas_get_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr; if ((nargs != 1) || (nret != 3)) { @@ -458,7 +548,7 @@ static void rtas_int_off(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr; if ((nargs != 1) || (nret != 1)) { @@ -484,7 +574,7 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t nargs, target_ulong args, uint32_t nret, target_ulong rets) { - struct ics_state *ics = spapr->icp->ics; + ICSState *ics = spapr->icp->ics; uint32_t nr; if ((nargs != 1) || (nret != 1)) { @@ -506,32 +596,27 @@ static void rtas_int_on(PowerPCCPU *cpu, sPAPREnvironment *spapr, rtas_st(rets, 0, 0); /* Success */ } -static void xics_reset(void *opaque) +/* + * XICS + */ + +static void xics_reset(DeviceState *d) { - struct icp_state *icp = (struct icp_state *)opaque; - struct ics_state *ics = icp->ics; + XICSState *icp = XICS(d); int i; for (i = 0; i < icp->nr_servers; i++) { - icp->ss[i].xirr = 0; - icp->ss[i].pending_priority = 0xff; - icp->ss[i].mfrr = 0xff; - /* Make all outputs are deasserted */ - qemu_set_irq(icp->ss[i].output, 0); + device_reset(DEVICE(&icp->ss[i])); } - memset(ics->irqs, 0, sizeof(struct ics_irq_state) * ics->nr_irqs); - for (i = 0; i < ics->nr_irqs; i++) { - ics->irqs[i].priority = 0xff; - ics->irqs[i].saved_priority = 0xff; - } + device_reset(DEVICE(icp->ics)); } -void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu) +void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu) { CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; - struct icp_server_state *ss = &icp->ss[cs->cpu_index]; + ICPState *ss = &icp->ss[cs->cpu_index]; assert(cs->cpu_index < icp->nr_servers); @@ -551,37 +636,73 @@ void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu) } } -struct icp_state *xics_system_init(int nr_servers, int nr_irqs) +static void xics_realize(DeviceState *dev, Error **errp) { - struct icp_state *icp; - struct ics_state *ics; - - icp = g_malloc0(sizeof(*icp)); - icp->nr_servers = nr_servers; - icp->ss = g_malloc0(icp->nr_servers*sizeof(struct icp_server_state)); + XICSState *icp = XICS(dev); + ICSState *ics = icp->ics; + int i; - ics = g_malloc0(sizeof(*ics)); - ics->nr_irqs = nr_irqs; + ics->nr_irqs = icp->nr_irqs; ics->offset = XICS_IRQ_BASE; - ics->irqs = g_malloc0(nr_irqs * sizeof(struct ics_irq_state)); - ics->islsi = g_malloc0(nr_irqs * sizeof(bool)); - - icp->ics = ics; ics->icp = icp; + qdev_init_nofail(DEVICE(ics)); - ics->qirqs = qemu_allocate_irqs(ics_set_irq, ics, nr_irqs); + icp->ss = g_malloc0(icp->nr_servers*sizeof(ICPState)); + for (i = 0; i < icp->nr_servers; i++) { + char buffer[32]; + object_initialize(&icp->ss[i], TYPE_ICP); + snprintf(buffer, sizeof(buffer), "icp[%d]", i); + object_property_add_child(OBJECT(icp), buffer, OBJECT(&icp->ss[i]), NULL); + qdev_init_nofail(DEVICE(&icp->ss[i])); + } +} - spapr_register_hypercall(H_CPPR, h_cppr); - spapr_register_hypercall(H_IPI, h_ipi); - spapr_register_hypercall(H_XIRR, h_xirr); - spapr_register_hypercall(H_EOI, h_eoi); +static void xics_initfn(Object *obj) +{ + XICSState *xics = XICS(obj); + + xics->ics = ICS(object_new(TYPE_ICS)); + object_property_add_child(obj, "ics", OBJECT(xics->ics), NULL); +} + +static Property xics_properties[] = { + DEFINE_PROP_UINT32("nr_servers", XICSState, nr_servers, -1), + DEFINE_PROP_UINT32("nr_irqs", XICSState, nr_irqs, -1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void xics_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = xics_realize; + dc->props = xics_properties; + dc->reset = xics_reset; spapr_rtas_register("ibm,set-xive", rtas_set_xive); spapr_rtas_register("ibm,get-xive", rtas_get_xive); spapr_rtas_register("ibm,int-off", rtas_int_off); spapr_rtas_register("ibm,int-on", rtas_int_on); - qemu_register_reset(xics_reset, icp); + spapr_register_hypercall(H_CPPR, h_cppr); + spapr_register_hypercall(H_IPI, h_ipi); + spapr_register_hypercall(H_XIRR, h_xirr); + spapr_register_hypercall(H_EOI, h_eoi); +} + +static const TypeInfo xics_info = { + .name = TYPE_XICS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(XICSState), + .class_init = xics_class_init, + .instance_init = xics_initfn, +}; - return icp; +static void xics_register_types(void) +{ + type_register_static(&xics_info); + type_register_static(&ics_info); + type_register_static(&icp_info); } + +type_init(xics_register_types) diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index b25ed04..a542134 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -261,6 +261,7 @@ static void pci_i82378_class_init(ObjectClass *klass, void *data) k->subsystem_vendor_id = 0x0; k->subsystem_id = 0x0; dc->vmsd = &vmstate_pci_i82378; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = i82378_properties; } diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index d1921aa..5633d08 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -600,6 +600,7 @@ static void ich9_lpc_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = ich9_lpc_reset; k->init = ich9_lpc_initfn; dc->vmsd = &vmstate_ich9_lpc; diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 2174eaa..8fe4fcb 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -281,6 +281,7 @@ static void via_ac97_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIA_AC97; k->revision = 0x50; k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); dc->desc = "AC97"; } @@ -322,6 +323,7 @@ static void via_mc97_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIA_MC97; k->class_id = PCI_CLASS_COMMUNICATION_OTHER; k->revision = 0x30; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "MC97"; } @@ -401,6 +403,7 @@ static void via_pm_class_init(ObjectClass *klass, void *data) k->revision = 0x40; dc->desc = "PM"; dc->vmsd = &vmstate_acpi; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = via_pm_properties; } diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index bfafa51..1e8d183e 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -263,6 +263,7 @@ static void qdev_applesmc_class_init(ObjectClass *klass, void *data) dc->realize = applesmc_isa_realize; dc->reset = qdev_applesmc_isa_reset; dc->props = applesmc_isa_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo applesmc_isa_info = { diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c index d754cf1..9db5680 100644 --- a/hw/misc/debugexit.c +++ b/hw/misc/debugexit.c @@ -58,6 +58,7 @@ static void debug_exit_class_initfn(ObjectClass *klass, void *data) dc->realize = debug_exit_realizefn; dc->props = debug_exit_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo debug_exit_info = { diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 4a74856..2838866 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -821,6 +821,7 @@ static void ivshmem_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_MEMORY_RAM; dc->reset = ivshmem_reset; dc->props = ivshmem_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo ivshmem_info = { diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c index 5867c70..18e94e0 100644 --- a/hw/misc/pc-testdev.c +++ b/hw/misc/pc-testdev.c @@ -188,6 +188,7 @@ static void testdev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->realize = testdev_realizefn; } diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index d69ff33..ca53b3f 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -315,6 +315,7 @@ static void pci_testdev_class_init(ObjectClass *klass, void *data) k->revision = 0x00; k->class_id = PCI_CLASS_OTHERS; dc->desc = "PCI Test Device"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->reset = qdev_pci_testdev_reset; } diff --git a/hw/misc/sga.c b/hw/misc/sga.c index 08803e7..83d2fd9 100644 --- a/hw/misc/sga.c +++ b/hw/misc/sga.c @@ -47,6 +47,7 @@ static void sga_class_initfn(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); dc->realize = sga_realizefn; dc->desc = "Serial Graphics Adapter"; } diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c index ad8ce77..017e693 100644 --- a/hw/misc/vfio.c +++ b/hw/misc/vfio.c @@ -3299,6 +3299,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) dc->props = vfio_pci_dev_properties; dc->vmsd = &vfio_pci_vmstate; dc->desc = "VFIO-based PCI device assignment"; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); pdc->init = vfio_initfn; pdc->exit = vfio_exitfn; pdc->config_read = vfio_pci_read_config; diff --git a/hw/net/e1000.c b/hw/net/e1000.c index b952d8d..fdb1f89 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1400,6 +1400,7 @@ static void e1000_class_init(ObjectClass *klass, void *data) k->device_id = E1000_DEVID; k->revision = 0x03; k->class_id = PCI_CLASS_NETWORK_ETHERNET; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "Intel Gigabit Ethernet"; dc->reset = qdev_e1000_reset; dc->vmsd = &vmstate_e1000; diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index e0befb2..ffa60d5 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -47,6 +47,7 @@ #include "hw/nvram/eeprom93xx.h" #include "sysemu/sysemu.h" #include "sysemu/dma.h" +#include "qemu/bitops.h" /* QEMU sends frames smaller than 60 bytes to ethernet nics. * Such frames are rejected by real nics and their emulations. @@ -105,7 +106,6 @@ #define PCI_IO_SIZE 64 #define PCI_FLASH_SIZE (128 * KiB) -#define BIT(n) (1 << (n)) #define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m) /* The SCB accepts the following controls for the Tx and Rx units: */ @@ -2083,6 +2083,7 @@ static void eepro100_class_init(ObjectClass *klass, void *data) info = eepro100_get_class_by_name(object_class_get_name(klass)); + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->props = e100_properties; dc->desc = info->desc; k->vendor_id = PCI_VENDOR_ID_INTEL; diff --git a/hw/net/lance.c b/hw/net/lance.c index 98bcdfc..1be7b72 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -150,6 +150,7 @@ static void lance_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = lance_init; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "ethernet"; dc->reset = lance_reset; dc->vmsd = &vmstate_lance; diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index 9080850..61578ed 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -264,6 +264,7 @@ static void mipsnet_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = mipsnet_sysbus_init; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "MIPS Simulator network device"; dc->reset = mipsnet_sysbus_reset; dc->vmsd = &vmstate_mipsnet; diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index e3c8076..26b83ce 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -98,6 +98,7 @@ static void isa_ne2000_class_initfn(ObjectClass *klass, void *data) dc->realize = isa_ne2000_realizefn; dc->props = ne2000_isa_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo ne2000_isa_info = { diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index 8d43fd9..31afd28 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -772,6 +772,7 @@ static void ne2000_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_NETWORK_ETHERNET; dc->vmsd = &vmstate_pci_ne2000; dc->props = ne2000_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo ne2000_info = { diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 4637557..513f345 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -713,6 +713,7 @@ static void open_eth_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = sysbus_open_eth_init; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->desc = "Opencores 10/100 Mbit Ethernet"; dc->reset = qdev_open_eth_reset; dc->props = open_eth_properties; diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 6ef28f7..2c2301c 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -366,6 +366,7 @@ static void pcnet_class_init(ObjectClass *klass, void *data) dc->reset = pci_reset; dc->vmsd = &vmstate_pci_pcnet; dc->props = pcnet_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo pcnet_info = { diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 6552034..ee3b690 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -3563,6 +3563,7 @@ static void rtl8139_class_init(ObjectClass *klass, void *data) dc->reset = rtl8139_reset; dc->vmsd = &vmstate_rtl8139; dc->props = rtl8139_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo rtl8139_info = { diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 03a09f2..46f7d5f 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -81,9 +81,9 @@ typedef struct VIOsPAPRVLANDevice { VIOsPAPRDevice sdev; NICConf nicconf; NICState *nic; - int isopen; + bool isopen; target_ulong buf_list; - int add_buf_ptr, use_buf_ptr, rx_bufs; + uint32_t add_buf_ptr, use_buf_ptr, rx_bufs; target_ulong rxq_ptr; } VIOsPAPRVLANDevice; @@ -500,6 +500,25 @@ static Property spapr_vlan_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_llan = { + .name = "spapr_llan", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_SPAPR_VIO(sdev, VIOsPAPRVLANDevice), + /* LLAN state */ + VMSTATE_BOOL(isopen, VIOsPAPRVLANDevice), + VMSTATE_UINTTL(buf_list, VIOsPAPRVLANDevice), + VMSTATE_UINT32(add_buf_ptr, VIOsPAPRVLANDevice), + VMSTATE_UINT32(use_buf_ptr, VIOsPAPRVLANDevice), + VMSTATE_UINT32(rx_bufs, VIOsPAPRVLANDevice), + VMSTATE_UINTTL(rxq_ptr, VIOsPAPRVLANDevice), + + VMSTATE_END_OF_LIST() + }, +}; + static void spapr_vlan_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -514,6 +533,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) k->signal_mask = 0x1; dc->props = spapr_vlan_properties; k->rtce_window_size = 0x10000000; + dc->vmsd = &vmstate_spapr_llan; } static const TypeInfo spapr_vlan_info = { diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 679f50c..aa1880c 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1638,6 +1638,7 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_net_device_exit; dc->props = virtio_net_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); vdc->init = virtio_net_device_init; vdc->get_config = virtio_net_get_config; vdc->set_config = virtio_net_set_config; diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 0f3c58c..49c2466 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2453,6 +2453,7 @@ static void vmxnet3_class_init(ObjectClass *class, void *data) dc->reset = vmxnet3_qdev_reset; dc->vmsd = &vmstate_vmxnet3; dc->props = vmxnet3_properties; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo vmxnet3_info = { diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index b98bfb0..0e521a8 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -81,12 +81,14 @@ err_bridge: static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); k->is_bridge = 1; k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_INTEL_82801BA_11; k->revision = ICH9_D2P_A2_REVISION; k->init = i82801b11_bridge_initfn; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo i82801b11_bridge_info = { diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index bb541eb..47122c5 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -220,6 +220,7 @@ static void ioh3420_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_INTEL; k->device_id = PCI_DEVICE_ID_IOH_EPORT; k->revision = PCI_DEVICE_ID_IOH_REV; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "Intel IOH device id 3420 PCIE Root Port"; dc->reset = ioh3420_reset; dc->vmsd = &vmstate_ioh3420; diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 5f11323..a00642c 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -141,6 +141,7 @@ static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) dc->reset = qdev_pci_bridge_dev_reset; dc->props = pci_bridge_dev_properties; dc->vmsd = &pci_bridge_dev_vmstate; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo pci_bridge_dev_info = { diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 1810dd2..33eff37 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -187,6 +187,7 @@ static void xio3130_downstream_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_TI; k->device_id = PCI_DEVICE_ID_TI_XIO3130D; k->revision = XIO3130_REVISION; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "TI X3130 Downstream Port of PCI Express Switch"; dc->reset = xio3130_downstream_reset; dc->vmsd = &vmstate_xio3130_downstream; diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index 8e0d97a..e9969a9 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -161,6 +161,7 @@ static void xio3130_upstream_class_init(ObjectClass *klass, void *data) k->vendor_id = PCI_VENDOR_ID_TI; k->device_id = PCI_DEVICE_ID_TI_XIO3130U; k->revision = XIO3130_REVISION; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "TI X3130 Upstream Port of PCI Express Switch"; dc->reset = xio3130_upstream_reset; dc->vmsd = &vmstate_xio3130_upstream; diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c index 3756ce9..bef7be1 100644 --- a/hw/pci-host/apb.c +++ b/hw/pci-host/apb.c @@ -536,6 +536,7 @@ static void pbm_host_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = pci_pbm_init_device; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = pci_pbm_reset; } @@ -558,6 +559,7 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data) k->revision = 0x11; k->config_write = pci_bridge_write_config; k->is_bridge = 1; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->reset = pci_bridge_reset; dc->vmsd = &vmstate_pci_device; } diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 646204e..f00793d 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -407,6 +407,7 @@ static void e500_pcihost_class_init(ObjectClass *klass, void *data) SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); k->init = e500_pcihost_initfn; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->props = pcihost_properties; dc->vmsd = &vmstate_ppce500_pci; } diff --git a/hw/pci-host/prep.c b/hw/pci-host/prep.c index b41d564..09d3b32 100644 --- a/hw/pci-host/prep.c +++ b/hw/pci-host/prep.c @@ -210,6 +210,7 @@ static void raven_pcihost_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->realize = raven_pcihost_realizefn; dc->fw_name = "pci"; dc->no_user = 1; diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 6b1b3b7..69234de 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -78,6 +78,7 @@ static void q35_host_class_init(ObjectClass *klass, void *data) hc->root_bus_path = q35_host_root_bus_path; dc->realize = q35_host_realize; dc->props = mch_props; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "pci"; } @@ -306,6 +307,7 @@ static void mch_class_init(ObjectClass *klass, void *data) k->init = mch_init; k->config_write = mch_write_config; dc->reset = mch_reset; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->desc = "Host bridge"; dc->vmsd = &vmstate_mch; k->vendor_id = PCI_VENDOR_ID_INTEL; diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 48ae092..16bfab9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -32,6 +32,7 @@ #include "sysemu/cpus.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" +#include "mmu-hash64.h" #include "hw/boards.h" #include "hw/ppc/ppc.h" @@ -128,6 +129,34 @@ int spapr_allocate_irq_block(int num, bool lsi) return first; } +static XICSState *try_create_xics(const char *type, int nr_servers, + int nr_irqs) +{ + DeviceState *dev; + + dev = qdev_create(NULL, type); + qdev_prop_set_uint32(dev, "nr_servers", nr_servers); + qdev_prop_set_uint32(dev, "nr_irqs", nr_irqs); + if (qdev_init(dev) < 0) { + return NULL; + } + + return XICS(dev); +} + +static XICSState *xics_system_init(int nr_servers, int nr_irqs) +{ + XICSState *icp = NULL; + + icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs); + if (!icp) { + perror("Failed to create XICS\n"); + abort(); + } + + return icp; +} + static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; @@ -666,7 +695,7 @@ static void spapr_cpu_reset(void *opaque) env->spr[SPR_HIOR] = 0; - env->external_htab = spapr->htab; + env->external_htab = (uint8_t *)spapr->htab; env->htab_base = -1; env->htab_mask = HTAB_SIZE(spapr) - 1; env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab | @@ -710,6 +739,330 @@ static int spapr_vga_init(PCIBus *pci_bus) } } +static const VMStateDescription vmstate_spapr = { + .name = "spapr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(next_irq, sPAPREnvironment), + + /* RTC offset */ + VMSTATE_UINT64(rtc_offset, sPAPREnvironment), + + VMSTATE_END_OF_LIST() + }, +}; + +#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2)) +#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID) +#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY) +#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY)) + +static int htab_save_setup(QEMUFile *f, void *opaque) +{ + sPAPREnvironment *spapr = opaque; + + /* "Iteration" header */ + qemu_put_be32(f, spapr->htab_shift); + + if (spapr->htab) { + spapr->htab_save_index = 0; + spapr->htab_first_pass = true; + } else { + assert(kvm_enabled()); + + spapr->htab_fd = kvmppc_get_htab_fd(false); + if (spapr->htab_fd < 0) { + fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n", + strerror(errno)); + return -1; + } + } + + + return 0; +} + +static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr, + int64_t max_ns) +{ + int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; + int index = spapr->htab_save_index; + int64_t starttime = qemu_get_clock_ns(rt_clock); + + assert(spapr->htab_first_pass); + + do { + int chunkstart; + + /* Consume invalid HPTEs */ + while ((index < htabslots) + && !HPTE_VALID(HPTE(spapr->htab, index))) { + index++; + CLEAN_HPTE(HPTE(spapr->htab, index)); + } + + /* Consume valid HPTEs */ + chunkstart = index; + while ((index < htabslots) + && HPTE_VALID(HPTE(spapr->htab, index))) { + index++; + CLEAN_HPTE(HPTE(spapr->htab, index)); + } + + if (index > chunkstart) { + int n_valid = index - chunkstart; + + qemu_put_be32(f, chunkstart); + qemu_put_be16(f, n_valid); + qemu_put_be16(f, 0); + qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), + HASH_PTE_SIZE_64 * n_valid); + + if ((qemu_get_clock_ns(rt_clock) - starttime) > max_ns) { + break; + } + } + } while ((index < htabslots) && !qemu_file_rate_limit(f)); + + if (index >= htabslots) { + assert(index == htabslots); + index = 0; + spapr->htab_first_pass = false; + } + spapr->htab_save_index = index; +} + +static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr, + int64_t max_ns) +{ + bool final = max_ns < 0; + int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; + int examined = 0, sent = 0; + int index = spapr->htab_save_index; + int64_t starttime = qemu_get_clock_ns(rt_clock); + + assert(!spapr->htab_first_pass); + + do { + int chunkstart, invalidstart; + + /* Consume non-dirty HPTEs */ + while ((index < htabslots) + && !HPTE_DIRTY(HPTE(spapr->htab, index))) { + index++; + examined++; + } + + chunkstart = index; + /* Consume valid dirty HPTEs */ + while ((index < htabslots) + && HPTE_DIRTY(HPTE(spapr->htab, index)) + && HPTE_VALID(HPTE(spapr->htab, index))) { + CLEAN_HPTE(HPTE(spapr->htab, index)); + index++; + examined++; + } + + invalidstart = index; + /* Consume invalid dirty HPTEs */ + while ((index < htabslots) + && HPTE_DIRTY(HPTE(spapr->htab, index)) + && !HPTE_VALID(HPTE(spapr->htab, index))) { + CLEAN_HPTE(HPTE(spapr->htab, index)); + index++; + examined++; + } + + if (index > chunkstart) { + int n_valid = invalidstart - chunkstart; + int n_invalid = index - invalidstart; + + qemu_put_be32(f, chunkstart); + qemu_put_be16(f, n_valid); + qemu_put_be16(f, n_invalid); + qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), + HASH_PTE_SIZE_64 * n_valid); + sent += index - chunkstart; + + if (!final && (qemu_get_clock_ns(rt_clock) - starttime) > max_ns) { + break; + } + } + + if (examined >= htabslots) { + break; + } + + if (index >= htabslots) { + assert(index == htabslots); + index = 0; + } + } while ((examined < htabslots) && (!qemu_file_rate_limit(f) || final)); + + if (index >= htabslots) { + assert(index == htabslots); + index = 0; + } + + spapr->htab_save_index = index; + + return (examined >= htabslots) && (sent == 0) ? 1 : 0; +} + +#define MAX_ITERATION_NS 5000000 /* 5 ms */ +#define MAX_KVM_BUF_SIZE 2048 + +static int htab_save_iterate(QEMUFile *f, void *opaque) +{ + sPAPREnvironment *spapr = opaque; + int rc = 0; + + /* Iteration header */ + qemu_put_be32(f, 0); + + if (!spapr->htab) { + assert(kvm_enabled()); + + rc = kvmppc_save_htab(f, spapr->htab_fd, + MAX_KVM_BUF_SIZE, MAX_ITERATION_NS); + if (rc < 0) { + return rc; + } + } else if (spapr->htab_first_pass) { + htab_save_first_pass(f, spapr, MAX_ITERATION_NS); + } else { + rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS); + } + + /* End marker */ + qemu_put_be32(f, 0); + qemu_put_be16(f, 0); + qemu_put_be16(f, 0); + + return rc; +} + +static int htab_save_complete(QEMUFile *f, void *opaque) +{ + sPAPREnvironment *spapr = opaque; + + /* Iteration header */ + qemu_put_be32(f, 0); + + if (!spapr->htab) { + int rc; + + assert(kvm_enabled()); + + rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1); + if (rc < 0) { + return rc; + } + close(spapr->htab_fd); + spapr->htab_fd = -1; + } else { + htab_save_later_pass(f, spapr, -1); + } + + /* End marker */ + qemu_put_be32(f, 0); + qemu_put_be16(f, 0); + qemu_put_be16(f, 0); + + return 0; +} + +static int htab_load(QEMUFile *f, void *opaque, int version_id) +{ + sPAPREnvironment *spapr = opaque; + uint32_t section_hdr; + int fd = -1; + + if (version_id < 1 || version_id > 1) { + fprintf(stderr, "htab_load() bad version\n"); + return -EINVAL; + } + + section_hdr = qemu_get_be32(f); + + if (section_hdr) { + /* First section, just the hash shift */ + if (spapr->htab_shift != section_hdr) { + return -EINVAL; + } + return 0; + } + + if (!spapr->htab) { + assert(kvm_enabled()); + + fd = kvmppc_get_htab_fd(true); + if (fd < 0) { + fprintf(stderr, "Unable to open fd to restore KVM hash table: %s\n", + strerror(errno)); + } + } + + while (true) { + uint32_t index; + uint16_t n_valid, n_invalid; + + index = qemu_get_be32(f); + n_valid = qemu_get_be16(f); + n_invalid = qemu_get_be16(f); + + if ((index == 0) && (n_valid == 0) && (n_invalid == 0)) { + /* End of Stream */ + break; + } + + if ((index + n_valid + n_invalid) > + (HTAB_SIZE(spapr) / HASH_PTE_SIZE_64)) { + /* Bad index in stream */ + fprintf(stderr, "htab_load() bad index %d (%hd+%hd entries) " + "in htab stream (htab_shift=%d)\n", index, n_valid, n_invalid, + spapr->htab_shift); + return -EINVAL; + } + + if (spapr->htab) { + if (n_valid) { + qemu_get_buffer(f, HPTE(spapr->htab, index), + HASH_PTE_SIZE_64 * n_valid); + } + if (n_invalid) { + memset(HPTE(spapr->htab, index + n_valid), 0, + HASH_PTE_SIZE_64 * n_invalid); + } + } else { + int rc; + + assert(fd >= 0); + + rc = kvmppc_load_htab_chunk(f, fd, index, n_valid, n_invalid); + if (rc < 0) { + return rc; + } + } + } + + if (!spapr->htab) { + assert(fd >= 0); + close(fd); + } + + return 0; +} + +static SaveVMHandlers savevm_htab_handlers = { + .save_live_setup = htab_save_setup, + .save_live_iterate = htab_save_iterate, + .save_live_complete = htab_save_complete, + .load_state = htab_load, +}; + /* pSeries LPAR / sPAPR hardware init */ static void ppc_spapr_init(QEMUMachineInitArgs *args) { @@ -848,9 +1201,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Set up EPOW events infrastructure */ spapr_events_init(spapr); - /* Set up IOMMU */ - spapr_iommu_init(); - /* Set up VIO bus */ spapr->vio_bus = spapr_vio_bus_init(); @@ -953,6 +1303,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) spapr->entry_point = 0x100; + vmstate_register(NULL, 0, &vmstate_spapr, spapr); + register_savevm_live(NULL, "spapr/htab", -1, 1, + &savevm_htab_handlers, spapr); + /* Prepare the device tree */ spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, initrd_base, initrd_size, diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index ed32dec..67d6cd9 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -115,7 +115,7 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, } ppc_hash64_store_hpte1(env, hpte, ptel); /* eieio(); FIXME: need some sort of barrier for smp? */ - ppc_hash64_store_hpte0(env, hpte, pteh); + ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY); args[0] = pte_index + i; return H_SUCCESS; @@ -152,7 +152,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex, } *vp = v; *rp = r; - ppc_hash64_store_hpte0(env, hpte, 0); + ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY); rb = compute_tlbie_rb(v, r, ptex); ppc_tlb_invalidate_one(env, rb); return REMOVE_SUCCESS; @@ -282,11 +282,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr, r |= (flags << 48) & HPTE64_R_KEY_HI; r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO); rb = compute_tlbie_rb(v, r, pte_index); - ppc_hash64_store_hpte0(env, hpte, v & ~HPTE64_V_VALID); + ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY); ppc_tlb_invalidate_one(env, rb); ppc_hash64_store_hpte1(env, hpte, r); /* Don't need a memory barrier, due to qemu's global lock */ - ppc_hash64_store_hpte0(env, hpte, v); + ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY); return H_SUCCESS; } diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index 89b33a5..3d4a1fc 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -36,17 +36,6 @@ enum sPAPRTCEAccess { SPAPR_TCE_RW = 3, }; -struct sPAPRTCETable { - uint32_t liobn; - uint32_t window_size; - sPAPRTCE *table; - bool bypass; - int fd; - MemoryRegion iommu; - QLIST_ENTRY(sPAPRTCETable) list; -}; - - QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables; static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn) @@ -96,7 +85,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr) return (IOMMUTLBEntry) { .perm = IOMMU_NONE }; } - tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce; + tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT]; #ifdef DEBUG_TCE fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n", @@ -112,55 +101,97 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr) }; } +static int spapr_tce_table_pre_load(void *opaque) +{ + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque); + + tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT; + + return 0; +} + +static const VMStateDescription vmstate_spapr_tce_table = { + .name = "spapr_iommu", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_load = spapr_tce_table_pre_load, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable), + VMSTATE_UINT32_EQUAL(window_size, sPAPRTCETable), + + /* IOMMU state */ + VMSTATE_BOOL(bypass, sPAPRTCETable), + VMSTATE_VARRAY_UINT32(table, sPAPRTCETable, nb_table, 0, vmstate_info_uint64, uint64_t), + + VMSTATE_END_OF_LIST() + }, +}; + static MemoryRegionIOMMUOps spapr_iommu_ops = { .translate = spapr_tce_translate_iommu, }; -sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size) +static int spapr_tce_table_realize(DeviceState *dev) { - sPAPRTCETable *tcet; - - if (spapr_tce_find_by_liobn(liobn)) { - fprintf(stderr, "Attempted to create TCE table with duplicate" - " LIOBN 0x%x\n", liobn); - return NULL; - } - - if (!window_size) { - return NULL; - } - - tcet = g_malloc0(sizeof(*tcet)); - tcet->liobn = liobn; - tcet->window_size = window_size; + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); if (kvm_enabled()) { - tcet->table = kvmppc_create_spapr_tce(liobn, - window_size, + tcet->table = kvmppc_create_spapr_tce(tcet->liobn, + tcet->window_size, &tcet->fd); } if (!tcet->table) { - size_t table_size = (window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); + size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) + * sizeof(uint64_t); tcet->table = g_malloc0(table_size); } + tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT; #ifdef DEBUG_TCE fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, " "table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd); #endif - memory_region_init_iommu(&tcet->iommu, OBJECT(owner), &spapr_iommu_ops, + memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops, "iommu-spapr", UINT64_MAX); QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list); + return 0; +} + +sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size) +{ + sPAPRTCETable *tcet; + + if (spapr_tce_find_by_liobn(liobn)) { + fprintf(stderr, "Attempted to create TCE table with duplicate" + " LIOBN 0x%x\n", liobn); + return NULL; + } + + if (!window_size) { + return NULL; + } + + tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE)); + tcet->liobn = liobn; + tcet->window_size = window_size; + + object_property_add_child(OBJECT(owner), "tce-table", OBJECT(tcet), NULL); + + qdev_init_nofail(DEVICE(tcet)); + return tcet; } -void spapr_tce_free(sPAPRTCETable *tcet) +static void spapr_tce_table_finalize(Object *obj) { + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(obj); + QLIST_REMOVE(tcet, list); if (!kvm_enabled() || @@ -168,8 +199,6 @@ void spapr_tce_free(sPAPRTCETable *tcet) tcet->window_size) != 0)) { g_free(tcet->table); } - - g_free(tcet); } MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet) @@ -182,10 +211,11 @@ void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass) tcet->bypass = bypass; } -void spapr_tce_reset(sPAPRTCETable *tcet) +static void spapr_tce_reset(DeviceState *dev) { + sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev); size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT) - * sizeof(sPAPRTCE); + * sizeof(uint64_t); tcet->bypass = false; memset(tcet->table, 0, table_size); @@ -194,7 +224,6 @@ void spapr_tce_reset(sPAPRTCETable *tcet) static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, target_ulong tce) { - sPAPRTCE *tcep; IOMMUTLBEntry entry; if (ioba >= tcet->window_size) { @@ -203,8 +232,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba, return H_PARAMETER; } - tcep = tcet->table + (ioba >> SPAPR_TCE_PAGE_SHIFT); - tcep->tce = tce; + tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT] = tce; entry.target_as = &address_space_memory, entry.iova = ioba & ~SPAPR_TCE_PAGE_MASK; @@ -238,14 +266,6 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_PARAMETER; } -void spapr_iommu_init(void) -{ - QLIST_INIT(&spapr_tce_tables); - - /* hcall-tce */ - spapr_register_hypercall(H_PUT_TCE, h_put_tce); -} - int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size) { @@ -286,3 +306,31 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, return spapr_dma_dt(fdt, node_off, propname, tcet->liobn, 0, tcet->window_size); } + +static void spapr_tce_table_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->vmsd = &vmstate_spapr_tce_table; + dc->init = spapr_tce_table_realize; + dc->reset = spapr_tce_reset; + + QLIST_INIT(&spapr_tce_tables); + + /* hcall-tce */ + spapr_register_hypercall(H_PUT_TCE, h_put_tce); +} + +static TypeInfo spapr_tce_table_info = { + .name = TYPE_SPAPR_TCE_TABLE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(sPAPRTCETable), + .class_init = spapr_tce_table_class_init, + .instance_finalize = spapr_tce_table_finalize, +}; + +static void register_types(void) +{ + type_register_static(&spapr_tce_table_info); +} + +type_init(register_types); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index c880a75..3156fdd 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -645,7 +645,7 @@ static void spapr_phb_reset(DeviceState *qdev) sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); /* Reset the IOMMU state */ - spapr_tce_reset(sphb->tcet); + device_reset(DEVICE(sphb->tcet)); } static Property spapr_phb_properties[] = { @@ -662,6 +662,54 @@ static Property spapr_phb_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_pci_lsi = { + .name = "spapr_pci/lsi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32_EQUAL(irq, struct spapr_pci_lsi), + + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_pci_msi = { + .name = "spapr_pci/lsi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(config_addr, struct spapr_pci_msi), + VMSTATE_UINT32(irq, struct spapr_pci_msi), + VMSTATE_UINT32(nvec, struct spapr_pci_msi), + + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_spapr_pci = { + .name = "spapr_pci", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64_EQUAL(buid, sPAPRPHBState), + VMSTATE_UINT32_EQUAL(dma_liobn, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(mem_win_addr, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState), + VMSTATE_UINT64_EQUAL(msi_win_addr, sPAPRPHBState), + VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0, + vmstate_spapr_pci_lsi, struct spapr_pci_lsi), + VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0, + vmstate_spapr_pci_msi, struct spapr_pci_msi), + + VMSTATE_END_OF_LIST() + }, +}; + static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) { @@ -680,6 +728,7 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data) sdc->init = spapr_phb_init; dc->props = spapr_phb_properties; dc->reset = spapr_phb_reset; + dc->vmsd = &vmstate_spapr_pci; } static const TypeInfo spapr_phb_info = { diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 7c6f6e4..c3f85bf 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -316,7 +316,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq) static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev) { if (dev->tcet) { - spapr_tce_reset(dev->tcet); + device_reset(DEVICE(dev->tcet)); } free_crq(dev); } @@ -542,6 +542,26 @@ static const TypeInfo spapr_vio_bridge_info = { .class_init = spapr_vio_bridge_class_init, }; +const VMStateDescription vmstate_spapr_vio = { + .name = "spapr_vio", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + /* Sanity check */ + VMSTATE_UINT32_EQUAL(reg, VIOsPAPRDevice), + VMSTATE_UINT32_EQUAL(irq, VIOsPAPRDevice), + + /* General VIO device state */ + VMSTATE_UINTTL(signal_state, VIOsPAPRDevice), + VMSTATE_UINT64(crq.qladdr, VIOsPAPRDevice), + VMSTATE_UINT32(crq.qsize, VIOsPAPRDevice), + VMSTATE_UINT32(crq.qnext, VIOsPAPRDevice), + + VMSTATE_END_OF_LIST() + }, +}; + static void vio_spapr_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 2ac21d4..d7ec173 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -392,6 +392,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_AMD_SCSI; k->revision = 0x10; k->class_id = PCI_CLASS_STORAGE_SCSI; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "AMD Am53c974 PCscsi-PCI SCSI adapter"; dc->reset = esp_pci_hard_reset; dc->vmsd = &vmstate_esp_pci_scsi; @@ -512,6 +513,7 @@ static void dc390_class_init(ObjectClass *klass, void *data) k->init = dc390_scsi_init; k->config_read = dc390_read_config; k->config_write = dc390_write_config; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "Tekram DC-390 SCSI adapter"; } diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 94639b8..101e957 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -720,6 +720,7 @@ static void sysbus_esp_class_init(ObjectClass *klass, void *data) dc->realize = sysbus_esp_realize; dc->reset = sysbus_esp_hard_reset; dc->vmsd = &vmstate_sysbus_esp_scsi; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo sysbus_esp_info = { diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 776e31a..611f2aa 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2141,6 +2141,7 @@ static void lsi_class_init(ObjectClass *klass, void *data) k->subsystem_id = 0x1000; dc->reset = lsi_scsi_reset; dc->vmsd = &vmstate_lsi_scsi; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static const TypeInfo lsi_info = { diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index eb52164..a6d5285 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2213,6 +2213,7 @@ static void megasas_class_init(ObjectClass *oc, void *data) dc->props = megasas_properties; dc->reset = megasas_scsi_reset; dc->vmsd = &vmstate_megasas; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->desc = "LSI MegaRAID SAS 1078"; } diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index b5a863a..fbf9173 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1881,6 +1881,7 @@ const VMStateDescription vmstate_scsi_device = { static void scsi_device_class_init(ObjectClass *klass, void *data) { DeviceClass *k = DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_STORAGE, k->categories); k->bus_type = TYPE_SCSI_BUS; k->init = scsi_qdev_init; k->unplug = scsi_qdev_unplug; diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 55b44b9..3f4c53f 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -75,20 +75,19 @@ typedef struct vscsi_req { /* SCSI request tracking */ SCSIRequest *sreq; uint32_t qtag; /* qemu tag != srp tag */ - int lun; - int active; - long data_len; - int writing; - int senselen; + bool active; + uint32_t data_len; + bool writing; + uint32_t senselen; uint8_t sense[SCSI_SENSE_BUF_SIZE]; /* RDMA related bits */ uint8_t dma_fmt; - struct srp_direct_buf ext_desc; - struct srp_direct_buf *cur_desc; - struct srp_indirect_buf *ind_desc; - int local_desc; - int total_desc; + uint16_t local_desc; + uint16_t total_desc; + uint16_t cdb_offset; + uint16_t cur_desc_num; + uint16_t cur_desc_offset; } vscsi_req; #define TYPE_VIO_SPAPR_VSCSI_DEVICE "spapr-vscsi" @@ -217,6 +216,7 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, union viosrp_iu *iu = &req->iu; uint64_t tag = iu->srp.rsp.tag; int total_len = sizeof(iu->srp.rsp); + uint8_t sol_not = iu->srp.cmd.sol_not; dprintf("VSCSI: Sending resp status: 0x%x, " "res_in: %d, res_out: %d\n", status, res_in, res_out); @@ -249,7 +249,7 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, /* Handle success vs. failure */ iu->srp.rsp.status = status; if (status) { - iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x04) >> 2; + iu->srp.rsp.sol_not = (sol_not & 0x04) >> 2; if (req->senselen) { req->iu.srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; req->iu.srp.rsp.sense_data_len = cpu_to_be32(req->senselen); @@ -257,100 +257,145 @@ static int vscsi_send_rsp(VSCSIState *s, vscsi_req *req, total_len += req->senselen; } } else { - iu->srp.rsp.sol_not = (iu->srp.cmd.sol_not & 0x02) >> 1; + iu->srp.rsp.sol_not = (sol_not & 0x02) >> 1; } vscsi_send_iu(s, req, total_len, VIOSRP_SRP_FORMAT); return 0; } -static inline void vscsi_swap_desc(struct srp_direct_buf *desc) +static inline struct srp_direct_buf vscsi_swap_desc(struct srp_direct_buf desc) { - desc->va = be64_to_cpu(desc->va); - desc->len = be32_to_cpu(desc->len); + desc.va = be64_to_cpu(desc.va); + desc.len = be32_to_cpu(desc.len); + return desc; +} + +static int vscsi_fetch_desc(VSCSIState *s, struct vscsi_req *req, + unsigned n, unsigned buf_offset, + struct srp_direct_buf *ret) +{ + struct srp_cmd *cmd = &req->iu.srp.cmd; + + switch (req->dma_fmt) { + case SRP_NO_DATA_DESC: { + dprintf("VSCSI: no data descriptor\n"); + return 0; + } + case SRP_DATA_DESC_DIRECT: { + memcpy(ret, cmd->add_data + req->cdb_offset, sizeof(*ret)); + assert(req->cur_desc_num == 0); + dprintf("VSCSI: direct segment\n"); + break; + } + case SRP_DATA_DESC_INDIRECT: { + struct srp_indirect_buf *tmp = (struct srp_indirect_buf *) + (cmd->add_data + req->cdb_offset); + if (n < req->local_desc) { + *ret = tmp->desc_list[n]; + dprintf("VSCSI: indirect segment local tag=0x%x desc#%d/%d\n", + req->qtag, n, req->local_desc); + + } else if (n < req->total_desc) { + int rc; + struct srp_direct_buf tbl_desc = vscsi_swap_desc(tmp->table_desc); + unsigned desc_offset = n * sizeof(struct srp_direct_buf); + + if (desc_offset >= tbl_desc.len) { + dprintf("VSCSI: #%d is ouf of range (%d bytes)\n", + n, desc_offset); + return -1; + } + rc = spapr_vio_dma_read(&s->vdev, tbl_desc.va + desc_offset, + ret, sizeof(struct srp_direct_buf)); + if (rc) { + dprintf("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n", + rc); + return -1; + } + dprintf("VSCSI: indirect segment ext. tag=0x%x desc#%d/%d { va=%"PRIx64" len=%x }\n", + req->qtag, n, req->total_desc, tbl_desc.va, tbl_desc.len); + } else { + dprintf("VSCSI: Out of descriptors !\n"); + return 0; + } + break; + } + default: + fprintf(stderr, "VSCSI: Unknown format %x\n", req->dma_fmt); + return -1; + } + + *ret = vscsi_swap_desc(*ret); + if (buf_offset > ret->len) { + dprintf(" offset=%x is out of a descriptor #%d boundary=%x\n", + buf_offset, req->cur_desc_num, ret->len); + return -1; + } + ret->va += buf_offset; + ret->len -= buf_offset; + + dprintf(" cur=%d offs=%x ret { va=%"PRIx64" len=%x }\n", + req->cur_desc_num, req->cur_desc_offset, ret->va, ret->len); + + return ret->len ? 1 : 0; } static int vscsi_srp_direct_data(VSCSIState *s, vscsi_req *req, uint8_t *buf, uint32_t len) { - struct srp_direct_buf *md = req->cur_desc; + struct srp_direct_buf md; uint32_t llen; int rc = 0; - dprintf("VSCSI: direct segment 0x%x bytes, va=0x%llx desc len=0x%x\n", - len, (unsigned long long)md->va, md->len); + rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md); + if (rc < 0) { + return -1; + } else if (rc == 0) { + return 0; + } - llen = MIN(len, md->len); + llen = MIN(len, md.len); if (llen) { if (req->writing) { /* writing = to device = reading from memory */ - rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen); } else { - rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen); } } - md->len -= llen; - md->va += llen; if (rc) { return -1; } + req->cur_desc_offset += llen; + return llen; } static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, uint8_t *buf, uint32_t len) { - struct srp_direct_buf *td = &req->ind_desc->table_desc; - struct srp_direct_buf *md = req->cur_desc; + struct srp_direct_buf md; int rc = 0; uint32_t llen, total = 0; - dprintf("VSCSI: indirect segment 0x%x bytes, td va=0x%llx len=0x%x\n", - len, (unsigned long long)td->va, td->len); + dprintf("VSCSI: indirect segment 0x%x bytes\n", len); /* While we have data ... */ while (len) { - /* If we have a descriptor but it's empty, go fetch a new one */ - if (md && md->len == 0) { - /* More local available, use one */ - if (req->local_desc) { - md = ++req->cur_desc; - --req->local_desc; - --req->total_desc; - td->va += sizeof(struct srp_direct_buf); - } else { - md = req->cur_desc = NULL; - } - } - /* No descriptor at hand, fetch one */ - if (!md) { - if (!req->total_desc) { - dprintf("VSCSI: Out of descriptors !\n"); - break; - } - md = req->cur_desc = &req->ext_desc; - dprintf("VSCSI: Reading desc from 0x%llx\n", - (unsigned long long)td->va); - rc = spapr_vio_dma_read(&s->vdev, td->va, md, - sizeof(struct srp_direct_buf)); - if (rc) { - dprintf("VSCSI: spapr_vio_dma_read -> %d reading ext_desc\n", - rc); - break; - } - vscsi_swap_desc(md); - td->va += sizeof(struct srp_direct_buf); - --req->total_desc; + rc = vscsi_fetch_desc(s, req, req->cur_desc_num, req->cur_desc_offset, &md); + if (rc < 0) { + return -1; + } else if (rc == 0) { + break; } - dprintf("VSCSI: [desc va=0x%llx,len=0x%x] remaining=0x%x\n", - (unsigned long long)md->va, md->len, len); /* Perform transfer */ - llen = MIN(len, md->len); + llen = MIN(len, md.len); if (req->writing) { /* writing = to device = reading from memory */ - rc = spapr_vio_dma_read(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_read(&s->vdev, md.va, buf, llen); } else { - rc = spapr_vio_dma_write(&s->vdev, md->va, buf, llen); + rc = spapr_vio_dma_write(&s->vdev, md.va, buf, llen); } if (rc) { dprintf("VSCSI: spapr_vio_dma_r/w(%d) -> %d\n", req->writing, rc); @@ -361,10 +406,18 @@ static int vscsi_srp_indirect_data(VSCSIState *s, vscsi_req *req, len -= llen; buf += llen; + total += llen; - md->va += llen; - md->len -= llen; + + /* Update current position in the current descriptor */ + req->cur_desc_offset += llen; + if (md.len == llen) { + /* Go to the next descriptor if the current one finished */ + ++req->cur_desc_num; + req->cur_desc_offset = 0; + } } + return rc ? -1 : total; } @@ -412,14 +465,13 @@ static int data_out_desc_size(struct srp_cmd *cmd) static int vscsi_preprocess_desc(vscsi_req *req) { struct srp_cmd *cmd = &req->iu.srp.cmd; - int offset, i; - offset = cmd->add_cdb_len & ~3; + req->cdb_offset = cmd->add_cdb_len & ~3; if (req->writing) { req->dma_fmt = cmd->buf_fmt >> 4; } else { - offset += data_out_desc_size(cmd); + req->cdb_offset += data_out_desc_size(cmd); req->dma_fmt = cmd->buf_fmt & ((1U << 4) - 1); } @@ -427,31 +479,18 @@ static int vscsi_preprocess_desc(vscsi_req *req) case SRP_NO_DATA_DESC: break; case SRP_DATA_DESC_DIRECT: - req->cur_desc = (struct srp_direct_buf *)(cmd->add_data + offset); req->total_desc = req->local_desc = 1; - vscsi_swap_desc(req->cur_desc); - dprintf("VSCSI: using direct RDMA %s, 0x%x bytes MD: 0x%llx\n", - req->writing ? "write" : "read", - req->cur_desc->len, (unsigned long long)req->cur_desc->va); break; - case SRP_DATA_DESC_INDIRECT: - req->ind_desc = (struct srp_indirect_buf *)(cmd->add_data + offset); - vscsi_swap_desc(&req->ind_desc->table_desc); - req->total_desc = req->ind_desc->table_desc.len / - sizeof(struct srp_direct_buf); + case SRP_DATA_DESC_INDIRECT: { + struct srp_indirect_buf *ind_tmp = (struct srp_indirect_buf *) + (cmd->add_data + req->cdb_offset); + + req->total_desc = be32_to_cpu(ind_tmp->table_desc.len) / + sizeof(struct srp_direct_buf); req->local_desc = req->writing ? cmd->data_out_desc_cnt : - cmd->data_in_desc_cnt; - for (i = 0; i < req->local_desc; i++) { - vscsi_swap_desc(&req->ind_desc->desc_list[i]); - } - req->cur_desc = req->local_desc ? &req->ind_desc->desc_list[0] : NULL; - dprintf("VSCSI: using indirect RDMA %s, 0x%x bytes %d descs " - "(%d local) VA: 0x%llx\n", - req->writing ? "read" : "write", - be32_to_cpu(req->ind_desc->len), - req->total_desc, req->local_desc, - (unsigned long long)req->ind_desc->table_desc.va); + cmd->data_in_desc_cnt; break; + } default: fprintf(stderr, "vscsi_preprocess_desc: Unknown format %x\n", req->dma_fmt); @@ -499,8 +538,8 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re vscsi_req *req = sreq->hba_private; int32_t res_in = 0, res_out = 0; - dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x status=0x%x, req=%p\n", - reason, sreq->tag, status, req); + dprintf("VSCSI: SCSI cmd complete, tag=0x%x status=0x%x, req=%p\n", + sreq->tag, status, req); if (req == NULL) { fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag); return; @@ -509,7 +548,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re if (status == CHECK_CONDITION) { req->senselen = scsi_req_get_sense(req->sreq, req->sense, sizeof(req->sense)); - dprintf("VSCSI: Sense data, %d bytes:\n", len); + dprintf("VSCSI: Sense data, %d bytes:\n", req->senselen); dprintf(" %02x %02x %02x %02x %02x %02x %02x %02x\n", req->sense[0], req->sense[1], req->sense[2], req->sense[3], req->sense[4], req->sense[5], req->sense[6], req->sense[7]); @@ -540,6 +579,69 @@ static void vscsi_request_cancelled(SCSIRequest *sreq) vscsi_put_req(req); } +static const VMStateDescription vmstate_spapr_vscsi_req = { + .name = "spapr_vscsi_req", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_BUFFER(crq.raw, vscsi_req), + VMSTATE_BUFFER(iu.srp.reserved, vscsi_req), + VMSTATE_UINT32(qtag, vscsi_req), + VMSTATE_BOOL(active, vscsi_req), + VMSTATE_UINT32(data_len, vscsi_req), + VMSTATE_BOOL(writing, vscsi_req), + VMSTATE_UINT32(senselen, vscsi_req), + VMSTATE_BUFFER(sense, vscsi_req), + VMSTATE_UINT8(dma_fmt, vscsi_req), + VMSTATE_UINT16(local_desc, vscsi_req), + VMSTATE_UINT16(total_desc, vscsi_req), + VMSTATE_UINT16(cdb_offset, vscsi_req), + /*Restart SCSI request from the beginning for now */ + /*VMSTATE_UINT16(cur_desc_num, vscsi_req), + VMSTATE_UINT16(cur_desc_offset, vscsi_req),*/ + VMSTATE_END_OF_LIST() + }, +}; + +static void vscsi_save_request(QEMUFile *f, SCSIRequest *sreq) +{ + vscsi_req *req = sreq->hba_private; + assert(req->active); + + vmstate_save_state(f, &vmstate_spapr_vscsi_req, req); + + dprintf("VSCSI: saving tag=%u, current desc#%d, offset=%x\n", + req->qtag, req->cur_desc_num, req->cur_desc_offset); +} + +static void *vscsi_load_request(QEMUFile *f, SCSIRequest *sreq) +{ + SCSIBus *bus = sreq->bus; + VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(bus->qbus.parent); + vscsi_req *req; + int rc; + + assert(sreq->tag < VSCSI_REQ_LIMIT); + req = &s->reqs[sreq->tag]; + assert(!req->active); + + memset(req, 0, sizeof(*req)); + rc = vmstate_load_state(f, &vmstate_spapr_vscsi_req, req, 1); + if (rc) { + fprintf(stderr, "VSCSI: failed loading request tag#%u\n", sreq->tag); + return NULL; + } + assert(req->active); + + req->sreq = scsi_req_ref(sreq); + + dprintf("VSCSI: restoring tag=%u, current desc#%d, offset=%x\n", + req->qtag, req->cur_desc_num, req->cur_desc_offset); + + return req; +} + static void vscsi_process_login(VSCSIState *s, vscsi_req *req) { union viosrp_iu *iu = &req->iu; @@ -621,12 +723,11 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) } return 1; } - req->lun = lun; req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req); n = scsi_req_enqueue(req->sreq); - dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", - req->qtag, srp->cmd.cdb[0], id, lun, n); + dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x LUN %d ret: %d\n", + req->qtag, srp->cmd.cdb[0], lun, n); if (n) { /* Transfer direction must be set before preprocessing the @@ -895,7 +996,9 @@ static const struct SCSIBusInfo vscsi_scsi_info = { .transfer_data = vscsi_transfer_data, .complete = vscsi_command_complete, - .cancel = vscsi_request_cancelled + .cancel = vscsi_request_cancelled, + .save_request = vscsi_save_request, + .load_request = vscsi_load_request, }; static void spapr_vscsi_reset(VIOsPAPRDevice *dev) @@ -959,6 +1062,20 @@ static Property spapr_vscsi_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_spapr_vscsi = { + .name = "spapr_vscsi", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_SPAPR_VIO(vdev, VSCSIState), + /* VSCSI state */ + /* ???? */ + + VMSTATE_END_OF_LIST() + }, +}; + static void spapr_vscsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -973,6 +1090,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) k->signal_mask = 0x00000001; dc->props = spapr_vscsi_properties; k->rtce_window_size = 0x10000000; + dc->vmsd = &vmstate_spapr_vscsi; } static const TypeInfo spapr_vscsi_info = { diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 785e93f..9e770fb 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -267,6 +267,7 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = vhost_scsi_exit; dc->props = vhost_scsi_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = vhost_scsi_init; vdc->get_features = vhost_scsi_get_features; vdc->set_config = vhost_scsi_set_config; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 42cb73b..05da56b 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -669,8 +669,10 @@ static Property virtio_scsi_properties[] = { static void virtio_scsi_common_class_init(ObjectClass *klass, void *data) { VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); vdc->get_config = virtio_scsi_get_config; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } static void virtio_scsi_class_init(ObjectClass *klass, void *data) @@ -679,6 +681,7 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_scsi_device_exit; dc->props = virtio_scsi_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); vdc->init = virtio_scsi_device_init; vdc->set_config = virtio_scsi_set_config; vdc->get_features = virtio_scsi_get_features; diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index e1074e1..d42b359 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1197,6 +1197,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data) dc->reset = pvscsi_reset; dc->vmsd = &vmstate_pvscsi; dc->props = pvscsi_properties; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); k->config_write = pvscsi_write_config; } diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index deb6d47..aa913df 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -592,6 +592,7 @@ static void emulated_class_initfn(ObjectClass *klass, void *data) cc->exitfn = emulated_exitfn; cc->get_atr = emulated_get_atr; cc->apdu_from_guest = emulated_apdu_from_guest; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "emulated smartcard"; dc->props = emulated_card_properties; } diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index 5f01ff1..10f1d30 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -392,6 +392,7 @@ static void passthru_class_initfn(ObjectClass *klass, void *data) cc->exitfn = passthru_exitfn; cc->get_atr = passthru_get_atr; cc->apdu_from_guest = passthru_apdu_from_guest; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "passthrough smartcard"; dc->vmsd = &passthru_vmstate; dc->props = passthru_card_properties; diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 04933a9..c5420eb 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -673,6 +673,7 @@ static void usb_audio_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_usb_audio; dc->props = usb_audio_properties; + set_bit(DEVICE_CATEGORY_SOUND, dc->categories); k->product_desc = "QEMU USB Audio Interface"; k->usb_desc = &desc_audio; k->init = usb_audio_initfn; diff --git a/hw/usb/dev-bluetooth.c b/hw/usb/dev-bluetooth.c index 68cc1d4..f2fc2a8 100644 --- a/hw/usb/dev-bluetooth.c +++ b/hw/usb/dev-bluetooth.c @@ -553,6 +553,7 @@ static void usb_bt_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_bt_handle_data; uc->handle_destroy = usb_bt_handle_destroy; dc->vmsd = &vmstate_usb_bt; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); } static const TypeInfo bt_info = { diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 31f3cde..66c6331 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -658,6 +658,7 @@ static void usb_tablet_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Tablet"; dc->vmsd = &vmstate_usb_ptr; dc->props = usb_tablet_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo usb_tablet_info = { @@ -677,6 +678,7 @@ static void usb_mouse_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Mouse"; uc->usb_desc = &desc_mouse; dc->vmsd = &vmstate_usb_ptr; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo usb_mouse_info = { @@ -696,6 +698,7 @@ static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) uc->product_desc = "QEMU USB Keyboard"; uc->usb_desc = &desc_keyboard; dc->vmsd = &vmstate_usb_kbd; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo usb_keyboard_info = { diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 0b71abd..e865a98 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -574,6 +574,7 @@ static void usb_hub_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_hub_handle_control; uc->handle_data = usb_hub_handle_data; uc->handle_destroy = usb_hub_handle_destroy; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); dc->fw_name = "hub"; dc->vmsd = &vmstate_usb_hub; } diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index 5473ac2..660d774 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1429,6 +1429,7 @@ static void usb_net_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_net_handle_control; uc->handle_data = usb_net_handle_data; uc->handle_destroy = usb_net_handle_destroy; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->fw_name = "network"; dc->vmsd = &vmstate_usb_net; dc->props = net_properties; diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 2fc8a3b..0b150d4 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -590,6 +590,7 @@ static void usb_serial_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_serial_handle_data; dc->vmsd = &vmstate_usb_serial; dc->props = serial_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo serial_info = { @@ -617,6 +618,7 @@ static void usb_braille_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_serial_handle_data; dc->vmsd = &vmstate_usb_serial; dc->props = braille_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo braille_info = { diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index b33eb25..2233c54 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1449,6 +1449,7 @@ static void ccid_class_initfn(ObjectClass *klass, void *data) dc->desc = "CCID Rev 1.1 smartcard reader"; dc->vmsd = &ccid_vmstate; dc->props = ccid_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } static const TypeInfo ccid_info = { diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 1954811..a8dc2fa 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -746,6 +746,7 @@ static void usb_msd_class_initfn_common(ObjectClass *klass) uc->handle_reset = usb_msd_handle_reset; uc->handle_control = usb_msd_handle_control; uc->handle_data = usb_msd_handle_data; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_msd; } diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 6efab62..63ad12e 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -916,6 +916,7 @@ static void usb_uas_class_initfn(ObjectClass *klass, void *data) uc->handle_control = usb_uas_handle_control; uc->handle_data = usb_uas_handle_data; uc->handle_destroy = usb_uas_handle_destroy; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_uas; } diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 3be5cde..1b09235 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -362,6 +362,7 @@ static void usb_wacom_class_init(ObjectClass *klass, void *data) uc->handle_control = usb_wacom_handle_control; uc->handle_data = usb_wacom_handle_data; uc->handle_destroy = usb_wacom_handle_destroy; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->desc = "QEMU PenPartner Tablet"; dc->vmsd = &vmstate_usb_wacom; } diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 5d229bc..4d21a0b 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -140,11 +140,13 @@ static const TypeInfo ehci_pci_type_info = { static void ehci_data_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); EHCIPCIInfo *i = data; k->vendor_id = i->vendor_id; k->device_id = i->device_id; k->revision = i->revision; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static struct EHCIPCIInfo ehci_pci_info[] = { diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 54147b5..fe6eea5 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -70,6 +70,7 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data) dc->realize = usb_ehci_sysbus_realize; dc->vmsd = &vmstate_ehci_sysbus; dc->props = ehci_sysbus_properties; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_type_info = { @@ -85,7 +86,9 @@ static const TypeInfo ehci_type_info = { static void ehci_xlnx_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + set_bit(DEVICE_CATEGORY_USB, dc->categories); sec->capsbase = 0x100; sec->opregbase = 0x140; } @@ -99,9 +102,11 @@ static const TypeInfo ehci_xlnx_type_info = { static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sec->capsbase = 0x0; sec->opregbase = 0x10; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_exynos4210_type_info = { @@ -113,9 +118,11 @@ static const TypeInfo ehci_exynos4210_type_info = { static void ehci_tegra2_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sec->capsbase = 0x100; sec->opregbase = 0x140; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_tegra2_type_info = { @@ -183,11 +190,13 @@ static void fusbh200_ehci_init(Object *obj) static void fusbh200_ehci_class_init(ObjectClass *oc, void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sec->capsbase = 0x0; sec->opregbase = 0x10; sec->portscbase = 0x20; sec->portnr = 1; + set_bit(DEVICE_CATEGORY_USB, dc->categories); } static const TypeInfo ehci_fusbh200_type_info = { diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 2bab8ff..d438d64 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1917,6 +1917,7 @@ static void ohci_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB; k->class_id = PCI_CLASS_SERIAL_USB; k->no_hotplug = 1; + set_bit(DEVICE_CATEGORY_USB, dc->categories); dc->desc = "Apple USB Controller"; dc->props = ohci_pci_properties; } @@ -1939,6 +1940,7 @@ static void ohci_sysbus_class_init(ObjectClass *klass, void *data) DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = ohci_realize_pxa; + set_bit(DEVICE_CATEGORY_USB, dc->categories); dc->desc = "OHCI USB Controller"; dc->props = ohci_sysbus_properties; } diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 066072e..cb44abc 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1315,6 +1315,7 @@ static void uhci_class_init(ObjectClass *klass, void *data) k->no_hotplug = 1; dc->vmsd = &vmstate_uhci; dc->props = uhci_properties; + set_bit(DEVICE_CATEGORY_USB, dc->categories); u->info = *info; } diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 9ba3e3e..58f311d 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3591,6 +3591,7 @@ static void xhci_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_xhci; dc->props = xhci_properties; dc->reset = xhci_reset; + set_bit(DEVICE_CATEGORY_USB, dc->categories); k->init = usb_xhci_initfn; k->vendor_id = PCI_VENDOR_ID_NEC; k->device_id = PCI_DEVICE_ID_NEC_UPD720200; diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index e2f3cc8..f660770 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1351,6 +1351,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->flush_ep_queue = usb_host_flush_ep_queue; dc->vmsd = &vmstate_usb_host; dc->props = usb_host_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static TypeInfo usb_host_dev_info = { diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c index ca09a89..7901f4c 100644 --- a/hw/usb/host-linux.c +++ b/hw/usb/host-linux.c @@ -1530,6 +1530,7 @@ static void usb_host_class_initfn(ObjectClass *klass, void *data) uc->handle_destroy = usb_host_handle_destroy; dc->vmsd = &vmstate_usb_host; dc->props = usb_host_dev_properties; + set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); } static const TypeInfo usb_host_dev_info = { diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index a594e95..8b8c010 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2362,6 +2362,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) uc->ep_stopped = usbredir_ep_stopped; dc->vmsd = &usbredir_vmstate; dc->props = usbredir_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo usbredir_dev_info = { diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 337cfa5..aac7f83 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -392,6 +392,7 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_balloon_device_exit; dc->props = virtio_balloon_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->init = virtio_balloon_device_init; vdc->get_config = virtio_balloon_get_config; vdc->set_config = virtio_balloon_set_config; diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 54d6679..88cf994 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -370,6 +370,7 @@ static void virtio_mmio_class_init(ObjectClass *klass, void *data) dc->realize = virtio_mmio_realizefn; dc->reset = virtio_mmio_reset; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo virtio_mmio_info = { diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index c38cfd1..d37037e 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -911,6 +911,7 @@ static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_9P; pcidev_k->revision = VIRTIO_PCI_ABI_VERSION; pcidev_k->class_id = 0x2; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = virtio_9p_pci_properties; } @@ -1065,6 +1066,7 @@ static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = virtio_blk_pci_properties; k->init = virtio_blk_pci_init; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; @@ -1135,6 +1137,7 @@ static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_scsi_pci_init_pci; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = virtio_scsi_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; @@ -1191,6 +1194,7 @@ static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = vhost_scsi_pci_init_pci; + set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); dc->props = vhost_scsi_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_SCSI; @@ -1271,6 +1275,7 @@ static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_balloon_pci_init; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->props = virtio_balloon_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON; @@ -1356,6 +1361,7 @@ static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_serial_pci_init; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); dc->props = virtio_serial_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE; @@ -1417,6 +1423,7 @@ static void virtio_net_pci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_VIRTIO_NET; k->revision = VIRTIO_PCI_ABI_VERSION; k->class_id = PCI_CLASS_NETWORK_ETHERNET; + set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); dc->props = virtio_net_properties; vpciklass->init = virtio_net_pci_init; } @@ -1468,6 +1475,7 @@ static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); k->init = virtio_rng_pci_init; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->props = virtio_rng_pci_properties; pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET; diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index cb787c7..bac8421 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -207,6 +207,7 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); dc->exit = virtio_rng_device_exit; dc->props = virtio_rng_properties; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); vdc->init = virtio_rng_device_init; vdc->get_features = get_features; } diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index 85aebc2..2e064ba 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -451,6 +451,7 @@ static void i6300esb_class_init(ObjectClass *klass, void *data) k->class_id = PCI_CLASS_SYSTEM_OTHER; dc->reset = i6300esb_reset; dc->vmsd = &vmstate_i6300esb; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo i6300esb_info = { diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index c788554..e97b4c3 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -137,6 +137,7 @@ static void wdt_ib700_class_init(ObjectClass *klass, void *data) dc->realize = wdt_ib700_realize; dc->reset = wdt_ib700_reset; dc->vmsd = &vmstate_ib700; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo wdt_ib700_info = { diff --git a/hw/xen/xen_platform.c b/hw/xen/xen_platform.c index 6a8ba7e..79bf0b3 100644 --- a/hw/xen/xen_platform.c +++ b/hw/xen/xen_platform.c @@ -428,6 +428,7 @@ static void xen_platform_class_init(ObjectClass *klass, void *data) k->subsystem_vendor_id = PCI_VENDOR_ID_XEN; k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM; k->revision = 1; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "XEN platform pci device"; dc->reset = platform_reset; dc->vmsd = &vmstate_xen_platform; diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index d15a729..ca2d460 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -830,6 +830,7 @@ static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data) k->exit = xen_pt_unregister_device; k->config_read = xen_pt_pci_read_config; k->config_write = xen_pt_pci_write_config; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "Assign an host PCI device with Xen"; dc->props = xen_pci_passthrough_properties; }; diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 1e23dbf..93f9511 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -52,14 +52,14 @@ typedef struct sPAPRPHBState { sPAPRTCETable *tcet; AddressSpace iommu_as; - struct { + struct spapr_pci_lsi { uint32_t irq; } lsi_table[PCI_NUM_PINS]; - struct { + struct spapr_pci_msi { uint32_t config_addr; uint32_t irq; - int nvec; + uint32_t nvec; } msi_table[SPAPR_MSIX_MAX_DEVS]; QLIST_ENTRY(sPAPRPHBState) list; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index de95480..9fc1972 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -7,30 +7,36 @@ struct VIOsPAPRBus; struct sPAPRPHBState; struct sPAPRNVRAM; -struct icp_state; + +#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL typedef struct sPAPREnvironment { struct VIOsPAPRBus *vio_bus; QLIST_HEAD(, sPAPRPHBState) phbs; struct sPAPRNVRAM *nvram; - struct icp_state *icp; + XICSState *icp; hwaddr ram_limit; void *htab; - long htab_shift; + uint32_t htab_shift; hwaddr rma_size; int vrma_adjust; hwaddr fdt_addr, rtas_addr; long rtas_size; void *fdt_skel; target_ulong entry_point; - int next_irq; - int rtc_offset; + uint32_t next_irq; + uint64_t rtc_offset; char *cpu_model; bool has_graphics; uint32_t epow_irq; Notifier epow_notifier; + + /* Migration state */ + int htab_save_index; + bool htab_first_pass; + int htab_fd; } sPAPREnvironment; #define H_SUCCESS 0 @@ -334,10 +340,6 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, #define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT) #define SPAPR_TCE_PAGE_MASK (SPAPR_TCE_PAGE_SIZE - 1) -typedef struct sPAPRTCE { - uint64_t tce; -} sPAPRTCE; - #define SPAPR_VIO_BASE_LIOBN 0x00000000 #define SPAPR_PCI_BASE_LIOBN 0x80000000 @@ -345,14 +347,27 @@ typedef struct sPAPRTCE { typedef struct sPAPRTCETable sPAPRTCETable; -void spapr_iommu_init(void); +#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table" +#define SPAPR_TCE_TABLE(obj) \ + OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE) + +struct sPAPRTCETable { + DeviceState parent; + uint32_t liobn; + uint32_t window_size; + uint32_t nb_table; + uint64_t *table; + bool bypass; + int fd; + MemoryRegion iommu; + QLIST_ENTRY(sPAPRTCETable) list; +}; + void spapr_events_init(sPAPREnvironment *spapr); void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq); sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size); MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet); -void spapr_tce_free(sPAPRTCETable *tcet); -void spapr_tce_reset(sPAPRTCETable *tcet); void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass); int spapr_dma_dt(void *fdt, int node_off, const char *propname, uint32_t liobn, uint64_t window, uint32_t size); diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h index 3609327..46edc2a 100644 --- a/include/hw/ppc/spapr_vio.h +++ b/include/hw/ppc/spapr_vio.h @@ -134,4 +134,9 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus); void spapr_vio_quiesce(void); +extern const VMStateDescription vmstate_spapr_vio; + +#define VMSTATE_SPAPR_VIO(_f, _s) \ + VMSTATE_STRUCT(_f, _s, 0, vmstate_spapr_vio, VIOsPAPRDevice) + #endif /* _HW_SPAPR_VIO_H */ diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index 6bce042..66364c5 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -27,15 +27,77 @@ #if !defined(__XICS_H__) #define __XICS_H__ +#include "hw/sysbus.h" + +#define TYPE_XICS "xics" +#define XICS(obj) OBJECT_CHECK(XICSState, (obj), TYPE_XICS) + #define XICS_IPI 0x2 -#define XICS_IRQ_BASE 0x10 +#define XICS_BUID 0x1 +#define XICS_IRQ_BASE (XICS_BUID << 12) + +/* + * We currently only support one BUID which is our interrupt base + * (the kernel implementation supports more but we don't exploit + * that yet) + */ +typedef struct XICSState XICSState; +typedef struct ICPState ICPState; +typedef struct ICSState ICSState; +typedef struct ICSIRQState ICSIRQState; + +struct XICSState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + uint32_t nr_servers; + uint32_t nr_irqs; + ICPState *ss; + ICSState *ics; +}; + +#define TYPE_ICP "icp" +#define ICP(obj) OBJECT_CHECK(ICPState, (obj), TYPE_ICP) + +struct ICPState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t xirr; + uint8_t pending_priority; + uint8_t mfrr; + qemu_irq output; +}; + +#define TYPE_ICS "ics" +#define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS) + +struct ICSState { + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + uint32_t nr_irqs; + uint32_t offset; + qemu_irq *qirqs; + bool *islsi; + ICSIRQState *irqs; + XICSState *icp; +}; -struct icp_state; +struct ICSIRQState { + uint32_t server; + uint8_t priority; + uint8_t saved_priority; +#define XICS_STATUS_ASSERTED 0x1 +#define XICS_STATUS_SENT 0x2 +#define XICS_STATUS_REJECTED 0x4 +#define XICS_STATUS_MASKED_PENDING 0x8 + uint8_t status; +}; -qemu_irq xics_get_qirq(struct icp_state *icp, int irq); -void xics_set_irq_type(struct icp_state *icp, int irq, bool lsi); +qemu_irq xics_get_qirq(XICSState *icp, int irq); +void xics_set_irq_type(XICSState *icp, int irq, bool lsi); -struct icp_state *xics_system_init(int nr_servers, int nr_irqs); -void xics_cpu_setup(struct icp_state *icp, PowerPCCPU *cpu); +void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu); #endif /* __XICS_H__ */ diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h index 7fbffcb..46972f4 100644 --- a/include/hw/qdev-core.h +++ b/include/hw/qdev-core.h @@ -4,6 +4,7 @@ #include "qemu/queue.h" #include "qemu/option.h" #include "qemu/typedefs.h" +#include "qemu/bitmap.h" #include "qom/object.h" #include "hw/irq.h" #include "qapi/error.h" @@ -17,6 +18,34 @@ enum { #define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE) #define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE) +typedef enum DeviceCategory { + DEVICE_CATEGORY_BRIDGE, + DEVICE_CATEGORY_USB, + DEVICE_CATEGORY_STORAGE, + DEVICE_CATEGORY_NETWORK, + DEVICE_CATEGORY_INPUT, + DEVICE_CATEGORY_DISPLAY, + DEVICE_CATEGORY_SOUND, + DEVICE_CATEGORY_MISC, + DEVICE_CATEGORY_MAX +} DeviceCategory; + +static inline const char *qdev_category_get_name(DeviceCategory category) +{ + static const char *category_names[DEVICE_CATEGORY_MAX] = { + [DEVICE_CATEGORY_BRIDGE] = "Controller/Bridge/Hub", + [DEVICE_CATEGORY_USB] = "USB", + [DEVICE_CATEGORY_STORAGE] = "Storage", + [DEVICE_CATEGORY_NETWORK] = "Network", + [DEVICE_CATEGORY_INPUT] = "Input", + [DEVICE_CATEGORY_DISPLAY] = "Display", + [DEVICE_CATEGORY_SOUND] = "Sound", + [DEVICE_CATEGORY_MISC] = "Misc", + }; + + return category_names[category]; +}; + typedef int (*qdev_initfn)(DeviceState *dev); typedef int (*qdev_event)(DeviceState *dev); typedef void (*qdev_resetfn)(DeviceState *dev); @@ -80,6 +109,7 @@ typedef struct DeviceClass { ObjectClass parent_class; /*< public >*/ + DECLARE_BITMAP(categories, DEVICE_CATEGORY_MAX); const char *fw_name; const char *desc; Property *props; @@ -19,6 +19,7 @@ #include "qemu/bitops.h" #include "qom/object.h" #include "sysemu/kvm.h" +#include "trace.h" #include <assert.h> #include "exec/memory-internal.h" @@ -388,6 +389,7 @@ static void memory_region_oldmmio_read_accessor(MemoryRegion *mr, uint64_t tmp; tmp = mr->ops->old_mmio.read[ctz32(size)](mr->opaque, addr); + trace_memory_region_ops_read(mr, addr, tmp, size); *value |= (tmp & mask) << shift; } @@ -404,6 +406,7 @@ static void memory_region_read_accessor(MemoryRegion *mr, qemu_flush_coalesced_mmio_buffer(); } tmp = mr->ops->read(mr->opaque, addr, size); + trace_memory_region_ops_read(mr, addr, tmp, size); *value |= (tmp & mask) << shift; } @@ -417,6 +420,7 @@ static void memory_region_oldmmio_write_accessor(MemoryRegion *mr, uint64_t tmp; tmp = (*value >> shift) & mask; + trace_memory_region_ops_write(mr, addr, tmp, size); mr->ops->old_mmio.write[ctz32(size)](mr->opaque, addr, tmp); } @@ -433,6 +437,7 @@ static void memory_region_write_accessor(MemoryRegion *mr, qemu_flush_coalesced_mmio_buffer(); } tmp = (*value >> shift) & mask; + trace_memory_region_ops_write(mr, addr, tmp, size); mr->ops->write(mr->opaque, addr, tmp, size); } diff --git a/qapi-schema.json b/qapi-schema.json index f82d829..a51f7d2 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3362,15 +3362,15 @@ '*rows' : 'int' } } ## -# @ChardevMemory: +# @ChardevRingbuf: # -# Configuration info for memory chardevs +# Configuration info for ring buffer chardevs. # -# @size: #optional Ringbuffer size, must be power of two, default is 65536 +# @size: #optional ring buffer size, must be power of two, default is 65536 # # Since: 1.5 ## -{ 'type': 'ChardevMemory', 'data': { '*size' : 'int' } } +{ 'type': 'ChardevRingbuf', 'data': { '*size' : 'int' } } ## # @ChardevBackend: @@ -3397,7 +3397,9 @@ 'spicevmc' : 'ChardevSpiceChannel', 'spiceport' : 'ChardevSpicePort', 'vc' : 'ChardevVC', - 'memory' : 'ChardevMemory' } } + 'ringbuf': 'ChardevRingbuf', + # next one is just for compatibility + 'memory' : 'ChardevRingbuf' } } ## # @ChardevReturn: diff --git a/qdev-monitor.c b/qdev-monitor.c index e5adf6c..410cdcb 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -75,24 +75,27 @@ static bool qdev_class_has_alias(DeviceClass *dc) return (qdev_class_get_alias(dc) != NULL); } -static void qdev_print_devinfo(ObjectClass *klass, void *opaque) +static void qdev_print_class_devinfo(DeviceClass *dc) { - DeviceClass *dc; - bool *show_no_user = opaque; - - dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); + DeviceCategory category; - if (!dc || (show_no_user && !*show_no_user && dc->no_user)) { + if (!dc) { return; } - error_printf("name \"%s\"", object_class_get_name(klass)); + error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc))); if (dc->bus_type) { error_printf(", bus %s", dc->bus_type); } if (qdev_class_has_alias(dc)) { error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); } + error_printf(", categories"); + for (category = 0; category < DEVICE_CATEGORY_MAX; ++category) { + if (test_bit(category, dc->categories)) { + error_printf(" \"%s\"", qdev_category_get_name(category)); + } + } if (dc->desc) { error_printf(", desc \"%s\"", dc->desc); } @@ -102,6 +105,15 @@ static void qdev_print_devinfo(ObjectClass *klass, void *opaque) error_printf("\n"); } +static void qdev_print_devinfo(ObjectClass *klass, void *opaque) +{ + DeviceClass *dc; + + dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE); + + qdev_print_class_devinfo(dc); +} + static int set_property(const char *name, const char *value, void *opaque) { DeviceState *dev = opaque; @@ -139,6 +151,21 @@ static const char *find_typename_by_alias(const char *alias) return NULL; } +static void qdev_print_category_devices(DeviceCategory category) +{ + DeviceClass *dc; + GSList *list, *curr; + + list = object_class_get_list(TYPE_DEVICE, false); + for (curr = list; curr; curr = g_slist_next(curr)) { + dc = (DeviceClass *)object_class_dynamic_cast(curr->data, TYPE_DEVICE); + if (!dc->no_user && test_bit(category, dc->categories)) { + qdev_print_class_devinfo(dc); + } + } + g_slist_free(list); +} + int qdev_device_help(QemuOpts *opts) { const char *driver; @@ -147,8 +174,11 @@ int qdev_device_help(QemuOpts *opts) driver = qemu_opt_get(opts, "driver"); if (driver && is_help_option(driver)) { - bool show_no_user = false; - object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user); + DeviceCategory category; + for (category = 0; category < DEVICE_CATEGORY_MAX; ++category) { + qdev_print_category_devices(category); + } + return 1; } diff --git a/qemu-char.c b/qemu-char.c index c86ce4b..3f606c9 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2783,8 +2783,8 @@ static void ringbuf_chr_close(struct CharDriverState *chr) chr->opaque = NULL; } -static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts, - Error **errp) +static CharDriverState *qemu_chr_open_ringbuf(ChardevRingbuf *opts, + Error **errp) { CharDriverState *chr; RingBufCharDriver *d; @@ -2796,7 +2796,7 @@ static CharDriverState *qemu_chr_open_memory(ChardevMemory *opts, /* The size must be power of 2 */ if (d->size & (d->size - 1)) { - error_setg(errp, "size of memory chardev must be power of two"); + error_setg(errp, "size of ringbuf chardev must be power of two"); goto fail; } @@ -3105,17 +3105,17 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, backend->pipe->device = g_strdup(device); } -static void qemu_chr_parse_memory(QemuOpts *opts, ChardevBackend *backend, - Error **errp) +static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, + Error **errp) { int val; - backend->memory = g_new0(ChardevMemory, 1); + backend->ringbuf = g_new0(ChardevRingbuf, 1); val = qemu_opt_get_size(opts, "size", 0); if (val != 0) { - backend->memory->has_size = true; - backend->memory->size = val; + backend->ringbuf->has_size = true; + backend->ringbuf->size = val; } } @@ -3723,8 +3723,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend, case CHARDEV_BACKEND_KIND_VC: chr = vc_init(backend->vc); break; + case CHARDEV_BACKEND_KIND_RINGBUF: case CHARDEV_BACKEND_KIND_MEMORY: - chr = qemu_chr_open_memory(backend->memory, errp); + chr = qemu_chr_open_ringbuf(backend->ringbuf, errp); break; default: error_setg(errp, "unknown chardev backend (%d)", backend->kind); @@ -3774,8 +3775,8 @@ static void register_types(void) register_char_driver_qapi("null", CHARDEV_BACKEND_KIND_NULL, NULL); register_char_driver("socket", qemu_chr_open_socket); register_char_driver("udp", qemu_chr_open_udp); - register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY, - qemu_chr_parse_memory); + register_char_driver_qapi("ringbuf", CHARDEV_BACKEND_KIND_RINGBUF, + qemu_chr_parse_ringbuf); register_char_driver_qapi("file", CHARDEV_BACKEND_KIND_FILE, qemu_chr_parse_file_out); register_char_driver_qapi("stdio", CHARDEV_BACKEND_KIND_STDIO, @@ -3794,6 +3795,9 @@ static void register_types(void) qemu_chr_parse_pipe); register_char_driver_qapi("mux", CHARDEV_BACKEND_KIND_MUX, qemu_chr_parse_mux); + /* Bug-compatibility: */ + register_char_driver_qapi("memory", CHARDEV_BACKEND_KIND_MEMORY, + qemu_chr_parse_ringbuf); } type_init(register_types); diff --git a/qemu-options.hx b/qemu-options.hx index 25ecb55..d15338e 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1783,7 +1783,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, "-chardev msmouse,id=id[,mux=on|off]\n" "-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]\n" " [,mux=on|off]\n" - "-chardev memory,id=id[,size=size]\n" + "-chardev ringbuf,id=id[,size=size]\n" "-chardev file,id=id,path=path[,mux=on|off]\n" "-chardev pipe,id=id,path=path[,mux=on|off]\n" #ifdef _WIN32 @@ -1821,7 +1821,7 @@ Backend is one of: @option{udp}, @option{msmouse}, @option{vc}, -@option{memory}, +@option{ringbuf}, @option{file}, @option{pipe}, @option{console}, @@ -1930,7 +1930,7 @@ the console, in pixels. @option{cols} and @option{rows} specify that the console be sized to fit a text console with the given dimensions. -@item -chardev memory ,id=@var{id} [,size=@var{size}] +@item -chardev ringbuf ,id=@var{id} [,size=@var{size}] Create a ring buffer with fixed size @option{size}. @var{size} must be a power of two, and defaults to @code{64K}). diff --git a/scripts/qapi.py b/scripts/qapi.py index 38c808e..0ebea94 100644 --- a/scripts/qapi.py +++ b/scripts/qapi.py @@ -2,14 +2,17 @@ # QAPI helper library # # Copyright IBM, Corp. 2011 +# Copyright (c) 2013 Red Hat Inc. # # Authors: # Anthony Liguori <aliguori@us.ibm.com> +# Markus Armbruster <armbru@redhat.com> # # This work is licensed under the terms of the GNU GPLv2. # See the COPYING.LIB file in the top-level directory. from ordereddict import OrderedDict +import sys builtin_types = [ 'str', 'int', 'number', 'bool', @@ -32,99 +35,147 @@ builtin_type_qtypes = { 'uint64': 'QTYPE_QINT', } -def tokenize(data): - while len(data): - ch = data[0] - data = data[1:] - if ch in ['{', '}', ':', ',', '[', ']']: - yield ch - elif ch in ' \n': - None - elif ch == "'": - string = '' - esc = False - while True: - if (data == ''): - raise Exception("Mismatched quotes") - ch = data[0] - data = data[1:] - if esc: - string += ch - esc = False - elif ch == "\\": - esc = True - elif ch == "'": - break - else: - string += ch - yield string - -def parse(tokens): - if tokens[0] == '{': - ret = OrderedDict() - tokens = tokens[1:] - while tokens[0] != '}': - key = tokens[0] - tokens = tokens[1:] - - tokens = tokens[1:] # : - - value, tokens = parse(tokens) - - if tokens[0] == ',': - tokens = tokens[1:] - - ret[key] = value - tokens = tokens[1:] - return ret, tokens - elif tokens[0] == '[': - ret = [] - tokens = tokens[1:] - while tokens[0] != ']': - value, tokens = parse(tokens) - if tokens[0] == ',': - tokens = tokens[1:] - ret.append(value) - tokens = tokens[1:] - return ret, tokens - else: - return tokens[0], tokens[1:] - -def evaluate(string): - return parse(map(lambda x: x, tokenize(string)))[0] - -def get_expr(fp): - expr = '' - - for line in fp: - if line.startswith('#') or line == '\n': - continue - - if line.startswith(' '): - expr += line - elif expr: - yield expr - expr = line +class QAPISchemaError(Exception): + def __init__(self, schema, msg): + self.fp = schema.fp + self.msg = msg + self.line = self.col = 1 + for ch in schema.src[0:schema.pos]: + if ch == '\n': + self.line += 1 + self.col = 1 + elif ch == '\t': + self.col = (self.col + 7) % 8 + 1 + else: + self.col += 1 + + def __str__(self): + return "%s:%s:%s: %s" % (self.fp.name, self.line, self.col, self.msg) + +class QAPISchema: + + def __init__(self, fp): + self.fp = fp + self.src = fp.read() + if self.src == '' or self.src[-1] != '\n': + self.src += '\n' + self.cursor = 0 + self.exprs = [] + self.accept() + + while self.tok != None: + self.exprs.append(self.get_expr(False)) + + def accept(self): + while True: + self.tok = self.src[self.cursor] + self.pos = self.cursor + self.cursor += 1 + self.val = None + + if self.tok == '#': + self.cursor = self.src.find('\n', self.cursor) + elif self.tok in ['{', '}', ':', ',', '[', ']']: + return + elif self.tok == "'": + string = '' + esc = False + while True: + ch = self.src[self.cursor] + self.cursor += 1 + if ch == '\n': + raise QAPISchemaError(self, + 'Missing terminating "\'"') + if esc: + string += ch + esc = False + elif ch == "\\": + esc = True + elif ch == "'": + self.val = string + return + else: + string += ch + elif self.tok == '\n': + if self.cursor == len(self.src): + self.tok = None + return + elif not self.tok.isspace(): + raise QAPISchemaError(self, 'Stray "%s"' % self.tok) + + def get_members(self): + expr = OrderedDict() + if self.tok == '}': + self.accept() + return expr + if self.tok != "'": + raise QAPISchemaError(self, 'Expected string or "}"') + while True: + key = self.val + self.accept() + if self.tok != ':': + raise QAPISchemaError(self, 'Expected ":"') + self.accept() + expr[key] = self.get_expr(True) + if self.tok == '}': + self.accept() + return expr + if self.tok != ',': + raise QAPISchemaError(self, 'Expected "," or "}"') + self.accept() + if self.tok != "'": + raise QAPISchemaError(self, 'Expected string') + + def get_values(self): + expr = [] + if self.tok == ']': + self.accept() + return expr + if not self.tok in [ '{', '[', "'" ]: + raise QAPISchemaError(self, 'Expected "{", "[", "]" or string') + while True: + expr.append(self.get_expr(True)) + if self.tok == ']': + self.accept() + return expr + if self.tok != ',': + raise QAPISchemaError(self, 'Expected "," or "]"') + self.accept() + + def get_expr(self, nested): + if self.tok != '{' and not nested: + raise QAPISchemaError(self, 'Expected "{"') + if self.tok == '{': + self.accept() + expr = self.get_members() + elif self.tok == '[': + self.accept() + expr = self.get_values() + elif self.tok == "'": + expr = self.val + self.accept() else: - expr += line - - if expr: - yield expr + raise QAPISchemaError(self, 'Expected "{", "[" or string') + return expr def parse_schema(fp): + try: + schema = QAPISchema(fp) + except QAPISchemaError as e: + print >>sys.stderr, e + exit(1) + exprs = [] - for expr in get_expr(fp): - expr_eval = evaluate(expr) - - if expr_eval.has_key('enum'): - add_enum(expr_eval['enum']) - elif expr_eval.has_key('union'): - add_union(expr_eval) - add_enum('%sKind' % expr_eval['union']) - elif expr_eval.has_key('type'): - add_struct(expr_eval) - exprs.append(expr_eval) + for expr in schema.exprs: + if expr.has_key('enum'): + add_enum(expr['enum']) + elif expr.has_key('union'): + add_union(expr) + add_enum('%sKind' % expr['union']) + elif expr.has_key('type'): + add_struct(expr) + exprs.append(expr) return exprs diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h index fc0d737..f3c710a 100644 --- a/target-ppc/cpu-qom.h +++ b/target-ppc/cpu-qom.h @@ -109,4 +109,8 @@ hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +#ifndef CONFIG_USER_ONLY +extern const struct VMStateDescription vmstate_ppc_cpu; +#endif + #endif diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h index 6f51e1f..711db08 100644 --- a/target-ppc/cpu.h +++ b/target-ppc/cpu.h @@ -948,7 +948,7 @@ struct CPUPPCState { #if defined(TARGET_PPC64) /* PowerPC 64 SLB area */ ppc_slb_t slb[64]; - int slb_nr; + int32_t slb_nr; #endif /* segment registers */ hwaddr htab_base; @@ -957,11 +957,11 @@ struct CPUPPCState { /* externally stored hash table */ uint8_t *external_htab; /* BATs */ - int nb_BATs; + uint32_t nb_BATs; target_ulong DBAT[2][8]; target_ulong IBAT[2][8]; /* PowerPC TLB registers (for 4xx, e500 and 60x software driven TLBs) */ - int nb_tlb; /* Total number of TLB */ + int32_t nb_tlb; /* Total number of TLB */ int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */ int nb_ways; /* Number of ways in the TLB set */ int last_way; /* Last used way used to allocate TLB in a LRU way */ @@ -1176,8 +1176,6 @@ static inline CPUPPCState *cpu_init(const char *cpu_model) #define cpu_signal_handler cpu_ppc_signal_handler #define cpu_list ppc_cpu_list -#define CPU_SAVE_VERSION 4 - /* MMU modes definitions */ #define MMU_MODE0_SUFFIX _user #define MMU_MODE1_SUFFIX _kernel diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index b0099e1..27e2aaf 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -65,6 +65,7 @@ static int cap_one_reg; static int cap_epr; static int cap_ppc_watchdog; static int cap_papr; +static int cap_htab_fd; /* XXX We have a race condition where we actually have a level triggered * interrupt, but the infrastructure can't expose that yet, so the guest @@ -101,6 +102,7 @@ int kvm_arch_init(KVMState *s) cap_ppc_watchdog = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_WATCHDOG); /* Note: we don't set cap_papr here, because this capability is * only activated after this by kvmppc_set_papr() */ + cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); if (!cap_interrupt_level) { fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " @@ -1626,7 +1628,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd) return NULL; } - len = (window_size / SPAPR_TCE_PAGE_SIZE) * sizeof(sPAPRTCE); + len = (window_size / SPAPR_TCE_PAGE_SIZE) * sizeof(uint64_t); /* FIXME: round this up to page size */ table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); @@ -1649,7 +1651,7 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size) return -1; } - len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(sPAPRTCE); + len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(uint64_t); if ((munmap(table, len) < 0) || (close(fd) < 0)) { fprintf(stderr, "KVM: Unexpected error removing TCE table: %s", @@ -1788,6 +1790,73 @@ static int kvm_ppc_register_host_cpu_type(void) } +int kvmppc_get_htab_fd(bool write) +{ + struct kvm_get_htab_fd s = { + .flags = write ? KVM_GET_HTAB_WRITE : 0, + .start_index = 0, + }; + + if (!cap_htab_fd) { + fprintf(stderr, "KVM version doesn't support saving the hash table\n"); + return -1; + } + + return kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &s); +} + +int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns) +{ + int64_t starttime = qemu_get_clock_ns(rt_clock); + uint8_t buf[bufsize]; + ssize_t rc; + + do { + rc = read(fd, buf, bufsize); + if (rc < 0) { + fprintf(stderr, "Error reading data from KVM HTAB fd: %s\n", + strerror(errno)); + return rc; + } else if (rc) { + /* Kernel already retuns data in BE format for the file */ + qemu_put_buffer(f, buf, rc); + } + } while ((rc != 0) + && ((max_ns < 0) + || ((qemu_get_clock_ns(rt_clock) - starttime) < max_ns))); + + return (rc == 0) ? 1 : 0; +} + +int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, + uint16_t n_valid, uint16_t n_invalid) +{ + struct kvm_get_htab_header *buf; + size_t chunksize = sizeof(*buf) + n_valid*HASH_PTE_SIZE_64; + ssize_t rc; + + buf = alloca(chunksize); + /* This is KVM on ppc, so this is all big-endian */ + buf->index = index; + buf->n_valid = n_valid; + buf->n_invalid = n_invalid; + + qemu_get_buffer(f, (void *)(buf + 1), HASH_PTE_SIZE_64*n_valid); + + rc = write(fd, buf, chunksize); + if (rc < 0) { + fprintf(stderr, "Error writing KVM hash table: %s\n", + strerror(errno)); + return rc; + } + if (rc != chunksize) { + /* We should never get a short write on a single chunk */ + fprintf(stderr, "Short write, restoring KVM hash table\n"); + return -1; + } + return 0; +} + bool kvm_arch_stop_on_emulation_error(CPUState *cpu) { return true; diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 771cfbe..4ae7bf2 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -38,6 +38,10 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ int kvmppc_fixup_cpu(PowerPCCPU *cpu); bool kvmppc_has_cap_epr(void); +int kvmppc_get_htab_fd(bool write); +int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns); +int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, + uint16_t n_valid, uint16_t n_invalid); #else @@ -159,6 +163,24 @@ static inline bool kvmppc_has_cap_epr(void) { return false; } + +static inline int kvmppc_get_htab_fd(bool write) +{ + return -1; +} + +static inline int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, + int64_t max_ns) +{ + abort(); +} + +static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, + uint16_t n_valid, uint16_t n_invalid) +{ + abort(); +} + #endif #ifndef CONFIG_KVM diff --git a/target-ppc/machine.c b/target-ppc/machine.c index 2d10adb..12e1512 100644 --- a/target-ppc/machine.c +++ b/target-ppc/machine.c @@ -1,96 +1,12 @@ #include "hw/hw.h" #include "hw/boards.h" #include "sysemu/kvm.h" +#include "helper_regs.h" -void cpu_save(QEMUFile *f, void *opaque) +static int cpu_load_old(QEMUFile *f, void *opaque, int version_id) { - CPUPPCState *env = (CPUPPCState *)opaque; - unsigned int i, j; - uint32_t fpscr; - target_ulong xer; - - for (i = 0; i < 32; i++) - qemu_put_betls(f, &env->gpr[i]); -#if !defined(TARGET_PPC64) - for (i = 0; i < 32; i++) - qemu_put_betls(f, &env->gprh[i]); -#endif - qemu_put_betls(f, &env->lr); - qemu_put_betls(f, &env->ctr); - for (i = 0; i < 8; i++) - qemu_put_be32s(f, &env->crf[i]); - xer = cpu_read_xer(env); - qemu_put_betls(f, &xer); - qemu_put_betls(f, &env->reserve_addr); - qemu_put_betls(f, &env->msr); - for (i = 0; i < 4; i++) - qemu_put_betls(f, &env->tgpr[i]); - for (i = 0; i < 32; i++) { - union { - float64 d; - uint64_t l; - } u; - u.d = env->fpr[i]; - qemu_put_be64(f, u.l); - } - fpscr = env->fpscr; - qemu_put_be32s(f, &fpscr); - qemu_put_sbe32s(f, &env->access_type); -#if defined(TARGET_PPC64) - qemu_put_betls(f, &env->spr[SPR_ASR]); - qemu_put_sbe32s(f, &env->slb_nr); -#endif - qemu_put_betls(f, &env->spr[SPR_SDR1]); - for (i = 0; i < 32; i++) - qemu_put_betls(f, &env->sr[i]); - for (i = 0; i < 2; i++) - for (j = 0; j < 8; j++) - qemu_put_betls(f, &env->DBAT[i][j]); - for (i = 0; i < 2; i++) - for (j = 0; j < 8; j++) - qemu_put_betls(f, &env->IBAT[i][j]); - qemu_put_sbe32s(f, &env->nb_tlb); - qemu_put_sbe32s(f, &env->tlb_per_way); - qemu_put_sbe32s(f, &env->nb_ways); - qemu_put_sbe32s(f, &env->last_way); - qemu_put_sbe32s(f, &env->id_tlbs); - qemu_put_sbe32s(f, &env->nb_pids); - if (env->tlb.tlb6) { - // XXX assumes 6xx - for (i = 0; i < env->nb_tlb; i++) { - qemu_put_betls(f, &env->tlb.tlb6[i].pte0); - qemu_put_betls(f, &env->tlb.tlb6[i].pte1); - qemu_put_betls(f, &env->tlb.tlb6[i].EPN); - } - } - for (i = 0; i < 4; i++) - qemu_put_betls(f, &env->pb[i]); - for (i = 0; i < 1024; i++) - qemu_put_betls(f, &env->spr[i]); - qemu_put_be32s(f, &env->vscr); - qemu_put_be64s(f, &env->spe_acc); - qemu_put_be32s(f, &env->spe_fscr); - qemu_put_betls(f, &env->msr_mask); - qemu_put_be32s(f, &env->flags); - qemu_put_sbe32s(f, &env->error_code); - qemu_put_be32s(f, &env->pending_interrupts); - qemu_put_be32s(f, &env->irq_input_state); - for (i = 0; i < POWERPC_EXCP_NB; i++) - qemu_put_betls(f, &env->excp_vectors[i]); - qemu_put_betls(f, &env->excp_prefix); - qemu_put_betls(f, &env->ivor_mask); - qemu_put_betls(f, &env->ivpr_mask); - qemu_put_betls(f, &env->hreset_vector); - qemu_put_betls(f, &env->nip); - qemu_put_betls(f, &env->hflags); - qemu_put_betls(f, &env->hflags_nmsr); - qemu_put_sbe32s(f, &env->mmu_idx); - qemu_put_sbe32(f, 0); -} - -int cpu_load(QEMUFile *f, void *opaque, int version_id) -{ - CPUPPCState *env = (CPUPPCState *)opaque; + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; unsigned int i, j; target_ulong sdr1; uint32_t fpscr; @@ -177,3 +93,442 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) return 0; } + +static int get_avr(QEMUFile *f, void *pv, size_t size) +{ + ppc_avr_t *v = pv; + + v->u64[0] = qemu_get_be64(f); + v->u64[1] = qemu_get_be64(f); + + return 0; +} + +static void put_avr(QEMUFile *f, void *pv, size_t size) +{ + ppc_avr_t *v = pv; + + qemu_put_be64(f, v->u64[0]); + qemu_put_be64(f, v->u64[1]); +} + +const VMStateInfo vmstate_info_avr = { + .name = "avr", + .get = get_avr, + .put = put_avr, +}; + +#define VMSTATE_AVR_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_avr, ppc_avr_t) + +#define VMSTATE_AVR_ARRAY(_f, _s, _n) \ + VMSTATE_AVR_ARRAY_V(_f, _s, _n, 0) + +static void cpu_pre_save(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int i; + + env->spr[SPR_LR] = env->lr; + env->spr[SPR_CTR] = env->ctr; + env->spr[SPR_XER] = env->xer; +#if defined(TARGET_PPC64) + env->spr[SPR_CFAR] = env->cfar; +#endif + env->spr[SPR_BOOKE_SPEFSCR] = env->spe_fscr; + + for (i = 0; (i < 4) && (i < env->nb_BATs); i++) { + env->spr[SPR_DBAT0U + 2*i] = env->DBAT[0][i]; + env->spr[SPR_DBAT0U + 2*i + 1] = env->DBAT[1][i]; + env->spr[SPR_IBAT0U + 2*i] = env->IBAT[0][i]; + env->spr[SPR_IBAT0U + 2*i + 1] = env->IBAT[1][i]; + } + for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) { + env->spr[SPR_DBAT4U + 2*i] = env->DBAT[0][i+4]; + env->spr[SPR_DBAT4U + 2*i + 1] = env->DBAT[1][i+4]; + env->spr[SPR_IBAT4U + 2*i] = env->IBAT[0][i+4]; + env->spr[SPR_IBAT4U + 2*i + 1] = env->IBAT[1][i+4]; + } +} + +static int cpu_post_load(void *opaque, int version_id) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + int i; + + env->lr = env->spr[SPR_LR]; + env->ctr = env->spr[SPR_CTR]; + env->xer = env->spr[SPR_XER]; +#if defined(TARGET_PPC64) + env->cfar = env->spr[SPR_CFAR]; +#endif + env->spe_fscr = env->spr[SPR_BOOKE_SPEFSCR]; + + for (i = 0; (i < 4) && (i < env->nb_BATs); i++) { + env->DBAT[0][i] = env->spr[SPR_DBAT0U + 2*i]; + env->DBAT[1][i] = env->spr[SPR_DBAT0U + 2*i + 1]; + env->IBAT[0][i] = env->spr[SPR_IBAT0U + 2*i]; + env->IBAT[1][i] = env->spr[SPR_IBAT0U + 2*i + 1]; + } + for (i = 0; (i < 4) && ((i+4) < env->nb_BATs); i++) { + env->DBAT[0][i+4] = env->spr[SPR_DBAT4U + 2*i]; + env->DBAT[1][i+4] = env->spr[SPR_DBAT4U + 2*i + 1]; + env->IBAT[0][i+4] = env->spr[SPR_IBAT4U + 2*i]; + env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1]; + } + + /* Restore htab_base and htab_mask variables */ + ppc_store_sdr1(env, env->spr[SPR_SDR1]); + + hreg_compute_hflags(env); + hreg_compute_mem_idx(env); + + return 0; +} + +static bool fpu_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + return (cpu->env.insns_flags & PPC_FLOAT); +} + +static const VMStateDescription vmstate_fpu = { + .name = "cpu/fpu", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_FLOAT64_ARRAY(env.fpr, PowerPCCPU, 32), + VMSTATE_UINTTL(env.fpscr, PowerPCCPU), + VMSTATE_END_OF_LIST() + }, +}; + +static bool altivec_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + return (cpu->env.insns_flags & PPC_ALTIVEC); +} + +static const VMStateDescription vmstate_altivec = { + .name = "cpu/altivec", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_AVR_ARRAY(env.avr, PowerPCCPU, 32), + VMSTATE_UINT32(env.vscr, PowerPCCPU), + VMSTATE_END_OF_LIST() + }, +}; + +static bool vsx_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + return (cpu->env.insns_flags2 & PPC2_VSX); +} + +static const VMStateDescription vmstate_vsx = { + .name = "cpu/vsx", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64_ARRAY(env.vsr, PowerPCCPU, 32), + VMSTATE_END_OF_LIST() + }, +}; + +static bool sr_needed(void *opaque) +{ +#ifdef TARGET_PPC64 + PowerPCCPU *cpu = opaque; + + return !(cpu->env.mmu_model & POWERPC_MMU_64); +#else + return true; +#endif +} + +static const VMStateDescription vmstate_sr = { + .name = "cpu/sr", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINTTL_ARRAY(env.sr, PowerPCCPU, 32), + VMSTATE_END_OF_LIST() + }, +}; + +#ifdef TARGET_PPC64 +static int get_slbe(QEMUFile *f, void *pv, size_t size) +{ + ppc_slb_t *v = pv; + + v->esid = qemu_get_be64(f); + v->vsid = qemu_get_be64(f); + + return 0; +} + +static void put_slbe(QEMUFile *f, void *pv, size_t size) +{ + ppc_slb_t *v = pv; + + qemu_put_be64(f, v->esid); + qemu_put_be64(f, v->vsid); +} + +const VMStateInfo vmstate_info_slbe = { + .name = "slbe", + .get = get_slbe, + .put = put_slbe, +}; + +#define VMSTATE_SLB_ARRAY_V(_f, _s, _n, _v) \ + VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_slbe, ppc_slb_t) + +#define VMSTATE_SLB_ARRAY(_f, _s, _n) \ + VMSTATE_SLB_ARRAY_V(_f, _s, _n, 0) + +static bool slb_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + + /* We don't support any of the old segment table based 64-bit CPUs */ + return (cpu->env.mmu_model & POWERPC_MMU_64); +} + +static const VMStateDescription vmstate_slb = { + .name = "cpu/slb", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.slb_nr, PowerPCCPU), + VMSTATE_SLB_ARRAY(env.slb, PowerPCCPU, 64), + VMSTATE_END_OF_LIST() + } +}; +#endif /* TARGET_PPC64 */ + +static const VMStateDescription vmstate_tlb6xx_entry = { + .name = "cpu/tlb6xx_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINTTL(pte0, ppc6xx_tlb_t), + VMSTATE_UINTTL(pte1, ppc6xx_tlb_t), + VMSTATE_UINTTL(EPN, ppc6xx_tlb_t), + VMSTATE_END_OF_LIST() + }, +}; + +static bool tlb6xx_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + return env->nb_tlb && (env->tlb_type == TLB_6XX); +} + +static const VMStateDescription vmstate_tlb6xx = { + .name = "cpu/tlb6xx", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU), + VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlb6, PowerPCCPU, + env.nb_tlb, + vmstate_tlb6xx_entry, + ppc6xx_tlb_t), + VMSTATE_UINTTL_ARRAY(env.tgpr, PowerPCCPU, 4), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_tlbemb_entry = { + .name = "cpu/tlbemb_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT64(RPN, ppcemb_tlb_t), + VMSTATE_UINTTL(EPN, ppcemb_tlb_t), + VMSTATE_UINTTL(PID, ppcemb_tlb_t), + VMSTATE_UINTTL(size, ppcemb_tlb_t), + VMSTATE_UINT32(prot, ppcemb_tlb_t), + VMSTATE_UINT32(attr, ppcemb_tlb_t), + VMSTATE_END_OF_LIST() + }, +}; + +static bool tlbemb_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + return env->nb_tlb && (env->tlb_type == TLB_EMB); +} + +static bool pbr403_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + uint32_t pvr = cpu->env.spr[SPR_PVR]; + + return (pvr & 0xffff0000) == 0x00200000; +} + +static const VMStateDescription vmstate_pbr403 = { + .name = "cpu/pbr403", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINTTL_ARRAY(env.pb, PowerPCCPU, 4), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_tlbemb = { + .name = "cpu/tlb6xx", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU), + VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbe, PowerPCCPU, + env.nb_tlb, + vmstate_tlbemb_entry, + ppcemb_tlb_t), + /* 403 protection registers */ + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_pbr403, + .needed = pbr403_needed, + } , { + /* empty */ + } + } +}; + +static const VMStateDescription vmstate_tlbmas_entry = { + .name = "cpu/tlbmas_entry", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(mas8, ppcmas_tlb_t), + VMSTATE_UINT32(mas1, ppcmas_tlb_t), + VMSTATE_UINT64(mas2, ppcmas_tlb_t), + VMSTATE_UINT64(mas7_3, ppcmas_tlb_t), + VMSTATE_END_OF_LIST() + }, +}; + +static bool tlbmas_needed(void *opaque) +{ + PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; + + return env->nb_tlb && (env->tlb_type == TLB_MAS); +} + +static const VMStateDescription vmstate_tlbmas = { + .name = "cpu/tlbmas", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT32_EQUAL(env.nb_tlb, PowerPCCPU), + VMSTATE_STRUCT_VARRAY_POINTER_INT32(env.tlb.tlbm, PowerPCCPU, + env.nb_tlb, + vmstate_tlbmas_entry, + ppcmas_tlb_t), + VMSTATE_END_OF_LIST() + } +}; + +const VMStateDescription vmstate_ppc_cpu = { + .name = "cpu", + .version_id = 5, + .minimum_version_id = 5, + .minimum_version_id_old = 4, + .load_state_old = cpu_load_old, + .pre_save = cpu_pre_save, + .post_load = cpu_post_load, + .fields = (VMStateField []) { + /* Verify we haven't changed the pvr */ + VMSTATE_UINTTL_EQUAL(env.spr[SPR_PVR], PowerPCCPU), + + /* User mode architected state */ + VMSTATE_UINTTL_ARRAY(env.gpr, PowerPCCPU, 32), +#if !defined(TARGET_PPC64) + VMSTATE_UINTTL_ARRAY(env.gprh, PowerPCCPU, 32), +#endif + VMSTATE_UINT32_ARRAY(env.crf, PowerPCCPU, 8), + VMSTATE_UINTTL(env.nip, PowerPCCPU), + + /* SPRs */ + VMSTATE_UINTTL_ARRAY(env.spr, PowerPCCPU, 1024), + VMSTATE_UINT64(env.spe_acc, PowerPCCPU), + + /* Reservation */ + VMSTATE_UINTTL(env.reserve_addr, PowerPCCPU), + + /* Supervisor mode architected state */ + VMSTATE_UINTTL(env.msr, PowerPCCPU), + + /* Internal state */ + VMSTATE_UINTTL(env.hflags_nmsr, PowerPCCPU), + /* FIXME: access_type? */ + + /* Sanity checking */ + VMSTATE_UINTTL_EQUAL(env.msr_mask, PowerPCCPU), + VMSTATE_UINT64_EQUAL(env.insns_flags, PowerPCCPU), + VMSTATE_UINT64_EQUAL(env.insns_flags2, PowerPCCPU), + VMSTATE_UINT32_EQUAL(env.nb_BATs, PowerPCCPU), + VMSTATE_END_OF_LIST() + }, + .subsections = (VMStateSubsection []) { + { + .vmsd = &vmstate_fpu, + .needed = fpu_needed, + } , { + .vmsd = &vmstate_altivec, + .needed = altivec_needed, + } , { + .vmsd = &vmstate_vsx, + .needed = vsx_needed, + } , { + .vmsd = &vmstate_sr, + .needed = sr_needed, + } , { +#ifdef TARGET_PPC64 + .vmsd = &vmstate_slb, + .needed = slb_needed, + } , { +#endif /* TARGET_PPC64 */ + .vmsd = &vmstate_tlb6xx, + .needed = tlb6xx_needed, + } , { + .vmsd = &vmstate_tlbemb, + .needed = tlbemb_needed, + } , { + .vmsd = &vmstate_tlbmas, + .needed = tlbmas_needed, + } , { + /* empty */ + } + } +}; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 3c81798..0724226 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -8464,6 +8464,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_write_register = ppc_cpu_gdb_write_register; #ifndef CONFIG_USER_ONLY cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug; + cc->vmsd = &vmstate_ppc_cpu; #endif cc->gdb_num_core_regs = 71; diff --git a/tests/Makefile b/tests/Makefile index cdbb79e..d044908 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -83,6 +83,14 @@ gcov-files-arm-y += hw/tmp105.c check-qtest-ppc-y += tests/boot-order-test$(EXESUF) check-qtest-ppc64-y += tests/boot-order-test$(EXESUF) +check-qapi-schema-y := $(addprefix tests/qapi-schema/, \ + comments.json empty.json funny-char.json indented-expr.json \ + missing-colon.json missing-comma-list.json \ + missing-comma-object.json non-objects.json \ + qapi-schema-test.json quoted-structural-chars.json \ + trailing-comma-list.json trailing-comma-object.json \ + unclosed-list.json unclosed-object.json unclosed-string.json) + GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \ @@ -117,13 +125,13 @@ tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o tests/test-int128$(EXESUF): tests/test-int128.o tests/test-qapi-types.c tests/test-qapi-types.h :\ -$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") tests/test-qapi-visit.c tests/test-qapi-visit.h :\ -$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") tests/test-qmp-commands.h tests/test-qmp-marshal.c :\ -$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py +$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@") tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a @@ -171,6 +179,7 @@ check-help: @echo " make check-qtest-TARGET Run qtest tests for given target" @echo " make check-qtest Run qtest tests" @echo " make check-unit Run qobject tests" + @echo " make check-qapi-schema Run QAPI schema tests" @echo " make check-block Run block tests" @echo " make check-report.html Generates an HTML test report" @echo @@ -233,13 +242,24 @@ check-report.html: check-report.xml check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF) $< +.PHONY: check-tests/test-qapi.py +check-tests/test-qapi.py: tests/test-qapi.py + +.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y)) +$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json + $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py <$^ >$*.out 2>$*.err; echo $$? >$*.exit, " TEST $*.out") + @diff -q $(SRC_PATH)/$*.out $*.out + @diff -q $(SRC_PATH)/$*.err $*.err + @diff -q $(SRC_PATH)/$*.exit $*.exit + # Consolidated targets -.PHONY: check-qtest check-unit check +.PHONY: check-qapi-schema check-qtest check-unit check +check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y)) check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS)) check-unit: $(patsubst %,check-%, $(check-unit-y)) check-block: $(patsubst %,check-%, $(check-block-y)) -check: check-unit check-qtest +check: check-qapi-schema check-unit check-qtest -include $(wildcard tests/*.d) -include $(wildcard tests/libqos/*.d) diff --git a/tests/qapi-schema/comments.err b/tests/qapi-schema/comments.err new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/comments.err diff --git a/tests/qapi-schema/comments.exit b/tests/qapi-schema/comments.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/qapi-schema/comments.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/comments.json b/tests/qapi-schema/comments.json new file mode 100644 index 0000000..e643f3a --- /dev/null +++ b/tests/qapi-schema/comments.json @@ -0,0 +1,4 @@ +# Unindented comment +{ 'enum': 'Status', # Comment to the right of code + # Indented comment + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out new file mode 100644 index 0000000..e3bd904 --- /dev/null +++ b/tests/qapi-schema/comments.out @@ -0,0 +1,3 @@ +[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])] +['Status'] +[] diff --git a/tests/qapi-schema/empty.err b/tests/qapi-schema/empty.err new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/empty.err diff --git a/tests/qapi-schema/empty.exit b/tests/qapi-schema/empty.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/qapi-schema/empty.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/empty.json b/tests/qapi-schema/empty.json new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/empty.json diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out new file mode 100644 index 0000000..b7f89a4 --- /dev/null +++ b/tests/qapi-schema/empty.out @@ -0,0 +1,3 @@ +[] +[] +[] diff --git a/tests/qapi-schema/funny-char.err b/tests/qapi-schema/funny-char.err new file mode 100644 index 0000000..d3dd293 --- /dev/null +++ b/tests/qapi-schema/funny-char.err @@ -0,0 +1 @@ +<stdin>:2:36: Stray ";" diff --git a/tests/qapi-schema/funny-char.exit b/tests/qapi-schema/funny-char.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/funny-char.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/funny-char.json b/tests/qapi-schema/funny-char.json new file mode 100644 index 0000000..d4973a2 --- /dev/null +++ b/tests/qapi-schema/funny-char.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ]; } diff --git a/tests/qapi-schema/funny-char.out b/tests/qapi-schema/funny-char.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/funny-char.out diff --git a/tests/qapi-schema/indented-expr.err b/tests/qapi-schema/indented-expr.err new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/indented-expr.err diff --git a/tests/qapi-schema/indented-expr.exit b/tests/qapi-schema/indented-expr.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/qapi-schema/indented-expr.exit @@ -0,0 +1 @@ +0 diff --git a/tests/qapi-schema/indented-expr.json b/tests/qapi-schema/indented-expr.json new file mode 100644 index 0000000..d80af60 --- /dev/null +++ b/tests/qapi-schema/indented-expr.json @@ -0,0 +1,2 @@ +{ 'id' : 'eins' } + { 'id' : 'zwei' } diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out new file mode 100644 index 0000000..98af89a --- /dev/null +++ b/tests/qapi-schema/indented-expr.out @@ -0,0 +1,3 @@ +[OrderedDict([('id', 'eins')]), OrderedDict([('id', 'zwei')])] +[] +[] diff --git a/tests/qapi-schema/missing-colon.err b/tests/qapi-schema/missing-colon.err new file mode 100644 index 0000000..9f2a355 --- /dev/null +++ b/tests/qapi-schema/missing-colon.err @@ -0,0 +1 @@ +<stdin>:1:10: Expected ":" diff --git a/tests/qapi-schema/missing-colon.exit b/tests/qapi-schema/missing-colon.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/missing-colon.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/missing-colon.json b/tests/qapi-schema/missing-colon.json new file mode 100644 index 0000000..6fc27ce --- /dev/null +++ b/tests/qapi-schema/missing-colon.json @@ -0,0 +1,2 @@ +{ 'enum' 'Status', + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/missing-colon.out b/tests/qapi-schema/missing-colon.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/missing-colon.out diff --git a/tests/qapi-schema/missing-comma-list.err b/tests/qapi-schema/missing-comma-list.err new file mode 100644 index 0000000..4fe0700 --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.err @@ -0,0 +1 @@ +<stdin>:2:20: Expected "," or "]" diff --git a/tests/qapi-schema/missing-comma-list.exit b/tests/qapi-schema/missing-comma-list.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/missing-comma-list.json b/tests/qapi-schema/missing-comma-list.json new file mode 100644 index 0000000..1af39b2 --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good' 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/missing-comma-list.out b/tests/qapi-schema/missing-comma-list.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/missing-comma-list.out diff --git a/tests/qapi-schema/missing-comma-object.err b/tests/qapi-schema/missing-comma-object.err new file mode 100644 index 0000000..b0121b5 --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.err @@ -0,0 +1 @@ +<stdin>:2:3: Expected "," or "}" diff --git a/tests/qapi-schema/missing-comma-object.exit b/tests/qapi-schema/missing-comma-object.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/missing-comma-object.json b/tests/qapi-schema/missing-comma-object.json new file mode 100644 index 0000000..50f5178 --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status' + 'data': [ 'good', 'bad', 'ugly' ] } diff --git a/tests/qapi-schema/missing-comma-object.out b/tests/qapi-schema/missing-comma-object.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/missing-comma-object.out diff --git a/tests/qapi-schema/non-objects.err b/tests/qapi-schema/non-objects.err new file mode 100644 index 0000000..a6c2dc2 --- /dev/null +++ b/tests/qapi-schema/non-objects.err @@ -0,0 +1 @@ +<stdin>:1:1: Expected "{" diff --git a/tests/qapi-schema/non-objects.exit b/tests/qapi-schema/non-objects.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/non-objects.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/non-objects.json b/tests/qapi-schema/non-objects.json new file mode 100644 index 0000000..f3fa851 --- /dev/null +++ b/tests/qapi-schema/non-objects.json @@ -0,0 +1,2 @@ +'string' +[ ] diff --git a/tests/qapi-schema/non-objects.out b/tests/qapi-schema/non-objects.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/non-objects.out diff --git a/tests/qapi-schema/qapi-schema-test.err b/tests/qapi-schema/qapi-schema-test.err new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/qapi-schema-test.err diff --git a/tests/qapi-schema/qapi-schema-test.exit b/tests/qapi-schema/qapi-schema-test.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/qapi-schema/qapi-schema-test.exit @@ -0,0 +1 @@ +0 diff --git a/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json index 4434fa3..4434fa3 100644 --- a/qapi-schema-test.json +++ b/tests/qapi-schema/qapi-schema-test.json diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out new file mode 100644 index 0000000..fb00344 --- /dev/null +++ b/tests/qapi-schema/qapi-schema-test.out @@ -0,0 +1,19 @@ +[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]), + OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefOne'), ('data', OrderedDict([('integer', 'int'), ('string', 'str'), ('*enum1', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), + OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]), + OrderedDict([('union', 'UserDefUnion'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]), + OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]), + OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]), + OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]), + OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')])] +['EnumOne', 'UserDefUnionKind', 'UserDefNativeListUnionKind'] +[OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefOne'), ('data', OrderedDict([('integer', 'int'), ('string', 'str'), ('*enum1', 'EnumOne')]))]), + OrderedDict([('type', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]), + OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]), + OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))])] diff --git a/tests/qapi-schema/quoted-structural-chars.err b/tests/qapi-schema/quoted-structural-chars.err new file mode 100644 index 0000000..a6c2dc2 --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.err @@ -0,0 +1 @@ +<stdin>:1:1: Expected "{" diff --git a/tests/qapi-schema/quoted-structural-chars.exit b/tests/qapi-schema/quoted-structural-chars.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/quoted-structural-chars.json b/tests/qapi-schema/quoted-structural-chars.json new file mode 100644 index 0000000..9fe657a --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.json @@ -0,0 +1 @@ +'{' 'key1' ':' 'value1' ',' 'key2' ':' '[' ']' '}' diff --git a/tests/qapi-schema/quoted-structural-chars.out b/tests/qapi-schema/quoted-structural-chars.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/quoted-structural-chars.out diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py new file mode 100644 index 0000000..b3d1e1d --- /dev/null +++ b/tests/qapi-schema/test-qapi.py @@ -0,0 +1,27 @@ +# +# QAPI parser test harness +# +# Copyright (c) 2013 Red Hat Inc. +# +# Authors: +# Markus Armbruster <armbru@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. +# + +from qapi import * +from pprint import pprint +import sys + +try: + exprs = parse_schema(sys.stdin) +except SystemExit: + raise +except: + print >>sys.stderr, "Crashed:", sys.exc_info()[0] + exit(1) + +pprint(exprs) +pprint(enum_types) +pprint(struct_types) diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err new file mode 100644 index 0000000..ff839a3 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.err @@ -0,0 +1 @@ +<stdin>:2:36: Expected "{", "[" or string diff --git a/tests/qapi-schema/trailing-comma-list.exit b/tests/qapi-schema/trailing-comma-list.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/trailing-comma-list.json b/tests/qapi-schema/trailing-comma-list.json new file mode 100644 index 0000000..9b0c8bd --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly', ] } diff --git a/tests/qapi-schema/trailing-comma-list.out b/tests/qapi-schema/trailing-comma-list.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-list.out diff --git a/tests/qapi-schema/trailing-comma-object.err b/tests/qapi-schema/trailing-comma-object.err new file mode 100644 index 0000000..f540962 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.err @@ -0,0 +1 @@ +<stdin>:2:38: Expected string diff --git a/tests/qapi-schema/trailing-comma-object.exit b/tests/qapi-schema/trailing-comma-object.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/trailing-comma-object.json b/tests/qapi-schema/trailing-comma-object.json new file mode 100644 index 0000000..bbaea55 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.json @@ -0,0 +1,2 @@ +{ 'enum': 'Status', + 'data': [ 'good', 'bad', 'ugly' ], } diff --git a/tests/qapi-schema/trailing-comma-object.out b/tests/qapi-schema/trailing-comma-object.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/trailing-comma-object.out diff --git a/tests/qapi-schema/unclosed-list.err b/tests/qapi-schema/unclosed-list.err new file mode 100644 index 0000000..0e837a7 --- /dev/null +++ b/tests/qapi-schema/unclosed-list.err @@ -0,0 +1 @@ +<stdin>:1:20: Expected "," or "]" diff --git a/tests/qapi-schema/unclosed-list.exit b/tests/qapi-schema/unclosed-list.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/unclosed-list.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/unclosed-list.json b/tests/qapi-schema/unclosed-list.json new file mode 100644 index 0000000..e3e9566 --- /dev/null +++ b/tests/qapi-schema/unclosed-list.json @@ -0,0 +1 @@ +{ 'key': [ 'value' } diff --git a/tests/qapi-schema/unclosed-list.out b/tests/qapi-schema/unclosed-list.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/unclosed-list.out diff --git a/tests/qapi-schema/unclosed-object.err b/tests/qapi-schema/unclosed-object.err new file mode 100644 index 0000000..e6dc950 --- /dev/null +++ b/tests/qapi-schema/unclosed-object.err @@ -0,0 +1 @@ +<stdin>:1:21: Expected "," or "}" diff --git a/tests/qapi-schema/unclosed-object.exit b/tests/qapi-schema/unclosed-object.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/unclosed-object.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/unclosed-object.json b/tests/qapi-schema/unclosed-object.json new file mode 100644 index 0000000..8ac069d --- /dev/null +++ b/tests/qapi-schema/unclosed-object.json @@ -0,0 +1 @@ +{ 'key': [ 'value' ] diff --git a/tests/qapi-schema/unclosed-object.out b/tests/qapi-schema/unclosed-object.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/unclosed-object.out diff --git a/tests/qapi-schema/unclosed-string.err b/tests/qapi-schema/unclosed-string.err new file mode 100644 index 0000000..948d883 --- /dev/null +++ b/tests/qapi-schema/unclosed-string.err @@ -0,0 +1 @@ +<stdin>:1:11: Missing terminating "'" diff --git a/tests/qapi-schema/unclosed-string.exit b/tests/qapi-schema/unclosed-string.exit new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/qapi-schema/unclosed-string.exit @@ -0,0 +1 @@ +1 diff --git a/tests/qapi-schema/unclosed-string.json b/tests/qapi-schema/unclosed-string.json new file mode 100644 index 0000000..8c16b6b --- /dev/null +++ b/tests/qapi-schema/unclosed-string.json @@ -0,0 +1,2 @@ +{ 'text': 'lorem ips +} diff --git a/tests/qapi-schema/unclosed-string.out b/tests/qapi-schema/unclosed-string.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/qapi-schema/unclosed-string.out @@ -32,7 +32,7 @@ static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = { }; static enum TpmModel tpm_models[TPM_MAX_MODELS] = { - -1, + TPM_MODEL_MAX, }; int tpm_register_model(enum TpmModel model) @@ -40,7 +40,7 @@ int tpm_register_model(enum TpmModel model) int i; for (i = 0; i < TPM_MAX_MODELS; i++) { - if (tpm_models[i] == -1) { + if (tpm_models[i] == TPM_MODEL_MAX) { tpm_models[i] = model; return 0; } diff --git a/trace-events b/trace-events index 0f7c8b4..3856b5c 100644 --- a/trace-events +++ b/trace-events @@ -1165,6 +1165,10 @@ kvm_vm_ioctl(int type, void *arg) "type %d, arg %p" kvm_vcpu_ioctl(int cpu_index, int type, void *arg) "cpu_index %d, type %d, arg %p" kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d" +# memory.c +memory_region_ops_read(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u" +memory_region_ops_write(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u" + # qom/object.c object_dynamic_cast_assert(const char *type, const char *target, const char *file, int line, const char *func) "%s->%s (%s:%d:%s)" object_class_dynamic_cast_assert(const char *type, const char *target, const char *file, int line, const char *func) "%s->%s (%s:%d:%s)" |