aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--MAINTAINERS29
-rw-r--r--Makefile18
-rw-r--r--Makefile.hw1
-rw-r--r--Makefile.objs17
-rw-r--r--Makefile.target40
-rw-r--r--QMP/qmp-events.txt53
-rw-r--r--arch_init.c9
-rw-r--r--block.c119
-rw-r--r--block.h4
-rw-r--r--block/blkdebug.c4
-rw-r--r--block/blkverify.c4
-rw-r--r--block/qcow.c104
-rw-r--r--block/rbd.c22
-rw-r--r--block/stream.c269
-rw-r--r--block/vdi.c8
-rw-r--r--block_int.h47
-rw-r--r--blockdev.c359
-rw-r--r--blockdev.h8
-rwxr-xr-xconfigure68
-rw-r--r--console.h3
-rw-r--r--cpus.c6
-rw-r--r--default-configs/alpha-softmmu.mak2
-rw-r--r--default-configs/arm-softmmu.mak1
-rw-r--r--default-configs/i386-softmmu.mak2
-rw-r--r--default-configs/mips-softmmu.mak2
-rw-r--r--default-configs/mips64-linux-user.mak1
-rw-r--r--default-configs/mips64-softmmu.mak2
-rw-r--r--default-configs/mips64el-linux-user.mak1
-rw-r--r--default-configs/mips64el-softmmu.mak2
-rw-r--r--default-configs/mipsel-softmmu.mak2
-rw-r--r--default-configs/mipsn32-linux-user.mak1
-rw-r--r--default-configs/mipsn32el-linux-user.mak1
-rw-r--r--default-configs/pci.mak1
-rw-r--r--default-configs/ppc-softmmu.mak4
-rw-r--r--default-configs/ppc64-softmmu.mak1
-rw-r--r--default-configs/ppcemb-softmmu.mak1
-rw-r--r--default-configs/sparc64-softmmu.mak2
-rw-r--r--default-configs/x86_64-softmmu.mak2
-rw-r--r--docs/live-block-ops.txt58
-rw-r--r--exec-obsolete.h42
-rw-r--r--exec.c28
-rw-r--r--hmp-commands.hx56
-rw-r--r--hmp.c170
-rw-r--r--hmp.h9
-rw-r--r--hw/9pfs/virtio-9p-device.c48
-rw-r--r--hw/a9mpcore.c46
-rw-r--r--hw/ac97.c87
-rw-r--r--hw/acpi_piix4.c63
-rw-r--r--hw/adlib.c2
-rw-r--r--hw/ads7846.c20
-rw-r--r--hw/alpha_pci.c6
-rw-r--r--hw/alpha_typhoon.c21
-rw-r--r--hw/apb_pci.c84
-rw-r--r--hw/apic.c365
-rw-r--r--hw/apic.h1
-rw-r--r--hw/apic_common.c321
-rw-r--r--hw/apic_internal.h122
-rw-r--r--hw/applesmc.c34
-rw-r--r--hw/arm-misc.h17
-rw-r--r--hw/arm11mpcore.c75
-rw-r--r--hw/arm_boot.c65
-rw-r--r--hw/arm_gic.c68
-rw-r--r--hw/arm_l2x0.c35
-rw-r--r--hw/arm_mptimer.c35
-rw-r--r--hw/arm_sysctl.c35
-rw-r--r--hw/arm_timer.c54
-rw-r--r--hw/armv7m.c29
-rw-r--r--hw/armv7m_nvic.c42
-rw-r--r--hw/bitbang_i2c.c21
-rw-r--r--hw/boards.h1
-rw-r--r--hw/bonito.c55
-rw-r--r--hw/ccid-card-emulated.c48
-rw-r--r--hw/ccid-card-passthru.c41
-rw-r--r--hw/ccid.h27
-rw-r--r--hw/cirrus_vga.c115
-rw-r--r--hw/cirrus_vga_template.h102
-rw-r--r--hw/container.c20
-rw-r--r--hw/cs4231.c31
-rw-r--r--hw/cs4231a.c50
-rw-r--r--hw/debugcon.c32
-rw-r--r--hw/dec_pci.c82
-rw-r--r--hw/ds1225y.c33
-rw-r--r--hw/ds1338.c34
-rw-r--r--hw/e1000.c57
-rw-r--r--hw/eccmemctl.c33
-rw-r--r--hw/eepro100.c207
-rw-r--r--hw/empty_slot.c18
-rw-r--r--hw/es1370.c74
-rw-r--r--hw/escc.c47
-rw-r--r--hw/esp.c31
-rw-r--r--hw/etraxfs_eth.c37
-rw-r--r--hw/etraxfs_pic.c29
-rw-r--r--hw/etraxfs_ser.c23
-rw-r--r--hw/etraxfs_timer.c17
-rw-r--r--hw/fdc.c110
-rw-r--r--hw/framebuffer.c9
-rw-r--r--hw/fw_cfg.c37
-rw-r--r--hw/g364fb.c51
-rw-r--r--hw/grackle_pci.c49
-rw-r--r--hw/grlib_apbuart.c135
-rw-r--r--hw/grlib_gptimer.c35
-rw-r--r--hw/grlib_irqmp.c33
-rw-r--r--hw/gt64xxx.c43
-rw-r--r--hw/gus.c58
-rw-r--r--hw/hda-audio.c64
-rw-r--r--hw/highbank.c339
-rw-r--r--hw/hpet.c37
-rw-r--r--hw/i2c.c116
-rw-r--r--hw/i2c.h51
-rw-r--r--hw/i82374.c165
-rw-r--r--hw/i82378.c275
-rw-r--r--hw/i8254.c36
-rw-r--r--hw/i8259.c173
-rw-r--r--hw/i8259_common.c161
-rw-r--r--hw/i8259_internal.h82
-rw-r--r--hw/ide/ahci.c53
-rw-r--r--hw/ide/cmd646.c43
-rw-r--r--hw/ide/ich.c38
-rw-r--r--hw/ide/internal.h20
-rw-r--r--hw/ide/isa.c36
-rw-r--r--hw/ide/pci.c4
-rw-r--r--hw/ide/piix.c97
-rw-r--r--hw/ide/qdev.c136
-rw-r--r--hw/ide/via.c31
-rw-r--r--hw/integratorcp.c45
-rw-r--r--hw/intel-hda.c104
-rw-r--r--hw/intel-hda.h25
-rw-r--r--hw/ioapic.c149
-rw-r--r--hw/ioapic_common.c121
-rw-r--r--hw/ioapic_internal.h102
-rw-r--r--hw/ioh3420.c63
-rw-r--r--hw/isa-bus.c63
-rw-r--r--hw/isa.h21
-rw-r--r--hw/ivshmem.c51
-rw-r--r--hw/kvm/apic.c147
-rw-r--r--hw/kvm/clock.c (renamed from hw/kvmclock.c)27
-rw-r--r--hw/kvm/clock.h (renamed from hw/kvmclock.h)0
-rw-r--r--hw/kvm/i8259.c138
-rw-r--r--hw/kvm/ioapic.c125
-rw-r--r--hw/lan9118.c159
-rw-r--r--hw/lance.c37
-rw-r--r--hw/lm32_juart.c25
-rw-r--r--hw/lm32_pic.c23
-rw-r--r--hw/lm32_sys.c33
-rw-r--r--hw/lm32_timer.c35
-rw-r--r--hw/lm32_uart.c25
-rw-r--r--hw/lm832x.c37
-rw-r--r--hw/loader.c6
-rw-r--r--hw/lsi53c895a.c36
-rw-r--r--hw/m48t59.c75
-rw-r--r--hw/macio.c51
-rw-r--r--hw/marvell_88w8618_audio.c39
-rw-r--r--hw/max111x.c40
-rw-r--r--hw/max7310.c39
-rw-r--r--hw/mc146818rtc.c66
-rw-r--r--hw/milkymist-ac97.c23
-rw-r--r--hw/milkymist-hpdmc.c23
-rw-r--r--hw/milkymist-memcard.c23
-rw-r--r--hw/milkymist-minimac2.c41
-rw-r--r--hw/milkymist-pfpu.c23
-rw-r--r--hw/milkymist-softusb.c47
-rw-r--r--hw/milkymist-sysctl.c47
-rw-r--r--hw/milkymist-tmu2.c23
-rw-r--r--hw/milkymist-uart.c25
-rw-r--r--hw/milkymist-vgafb.c35
-rw-r--r--hw/milkymist-vgafb_template.h2
-rw-r--r--hw/mips_malta.c27
-rw-r--r--hw/mipsnet.c37
-rw-r--r--hw/mpc8544_guts.c18
-rw-r--r--hw/msi.c8
-rw-r--r--hw/msi.h2
-rw-r--r--hw/msix.c9
-rw-r--r--hw/msix.h2
-rw-r--r--hw/mst_fpga.c23
-rw-r--r--hw/musicpal.c182
-rw-r--r--hw/nand.c37
-rw-r--r--hw/ne2000-isa.c34
-rw-r--r--hw/ne2000.c41
-rw-r--r--hw/omap_gpio.c78
-rw-r--r--hw/omap_intc.c70
-rw-r--r--hw/onenand.c39
-rw-r--r--hw/opencores_eth.c35
-rw-r--r--hw/openpic.c30
-rw-r--r--hw/openpic.h2
-rw-r--r--hw/parallel.c34
-rw-r--r--hw/pc.c51
-rw-r--r--hw/pc.h9
-rw-r--r--hw/pc_piix.c75
-rw-r--r--hw/pci.c179
-rw-r--r--hw/pci.h84
-rw-r--r--hw/pci_bridge.c2
-rw-r--r--hw/pci_ids.h4
-rw-r--r--hw/pcie.c2
-rw-r--r--hw/pckbd.c22
-rw-r--r--hw/pcnet-pci.c43
-rw-r--r--hw/pcnet.c5
-rw-r--r--hw/piix4.c37
-rw-r--r--hw/piix_pci.c140
-rw-r--r--hw/pl011.c40
-rw-r--r--hw/pl022.c16
-rw-r--r--hw/pl031.c23
-rw-r--r--hw/pl041.c38
-rw-r--r--hw/pl050.c42
-rw-r--r--hw/pl061.c42
-rw-r--r--hw/pl080.c46
-rw-r--r--hw/pl110.c69
-rw-r--r--hw/pl181.c25
-rw-r--r--hw/pl190.c25
-rw-r--r--hw/ppc440.c106
-rw-r--r--hw/ppc440.h21
-rw-r--r--hw/ppc440_bamboo.c154
-rw-r--r--hw/ppc4xx_pci.c147
-rw-r--r--hw/ppc_newworld.c2
-rw-r--r--hw/ppc_prep.c82
-rw-r--r--hw/ppce500_pci.c46
-rw-r--r--hw/ppce500_spin.c18
-rw-r--r--hw/prep_pci.c184
-rw-r--r--hw/prep_pci.h11
-rw-r--r--hw/pxa2xx.c108
-rw-r--r--hw/pxa2xx_dma.c33
-rw-r--r--hw/pxa2xx_gpio.c33
-rw-r--r--hw/pxa2xx_pic.c23
-rw-r--r--hw/pxa2xx_timer.c74
-rw-r--r--hw/qdev-addr.c6
-rw-r--r--hw/qdev-monitor.c588
-rw-r--r--hw/qdev-properties.c132
-rw-r--r--hw/qdev.c1141
-rw-r--r--hw/qdev.h363
-rw-r--r--hw/qxl.c77
-rw-r--r--hw/realview.c20
-rw-r--r--hw/realview_gic.c24
-rw-r--r--hw/rtl8139.c47
-rw-r--r--hw/s390-virtio-bus.c156
-rw-r--r--hw/s390-virtio-bus.h19
-rw-r--r--hw/s390-virtio.c1
-rw-r--r--hw/sb16.c140
-rw-r--r--hw/sbi.c23
-rw-r--r--hw/scsi-bus.c104
-rw-r--r--hw/scsi-disk.c187
-rw-r--r--hw/scsi-generic.c41
-rw-r--r--hw/scsi.h30
-rw-r--r--hw/serial.c36
-rw-r--r--hw/sga.c21
-rw-r--r--hw/sh_pci.c41
-rw-r--r--hw/slavio_intctl.c23
-rw-r--r--hw/slavio_misc.c41
-rw-r--r--hw/slavio_timer.c33
-rw-r--r--hw/sm501.c11
-rw-r--r--hw/smbus.c85
-rw-r--r--hw/smbus.h40
-rw-r--r--hw/smbus_eeprom.c39
-rw-r--r--hw/smc91c111.c35
-rw-r--r--hw/spapr.c136
-rw-r--r--hw/spapr_llan.c43
-rw-r--r--hw/spapr_pci.c208
-rw-r--r--hw/spapr_vio.c85
-rw-r--r--hw/spapr_vio.h34
-rw-r--r--hw/spapr_vscsi.c39
-rw-r--r--hw/spapr_vty.c39
-rw-r--r--hw/sparc32_dma.c35
-rw-r--r--hw/spitz.c110
-rw-r--r--hw/ssd0303.c37
-rw-r--r--hw/ssd0323.c20
-rw-r--r--hw/ssi-sd.c20
-rw-r--r--hw/ssi.c39
-rw-r--r--hw/ssi.h18
-rw-r--r--hw/stellaris.c71
-rw-r--r--hw/stellaris_enet.c31
-rw-r--r--hw/strongarm.c148
-rw-r--r--hw/sun4c_intctl.c23
-rw-r--r--hw/sun4m.c92
-rw-r--r--hw/sun4m_iommu.c33
-rw-r--r--hw/sun4u.c82
-rw-r--r--hw/sysbus.c50
-rw-r--r--hw/sysbus.h23
-rw-r--r--hw/tcx.c74
-rw-r--r--hw/tmp105.c41
-rw-r--r--hw/tosa.c54
-rw-r--r--hw/tusb6010.c21
-rw-r--r--hw/twl92230.c39
-rw-r--r--hw/unin_pci.c220
-rw-r--r--hw/usb-audio.c715
-rw-r--r--hw/usb-bt.c57
-rw-r--r--hw/usb-bus.c196
-rw-r--r--hw/usb-ccid.c142
-rw-r--r--hw/usb-desc.c161
-rw-r--r--hw/usb-desc.h5
-rw-r--r--hw/usb-ehci.c70
-rw-r--r--hw/usb-hid.c123
-rw-r--r--hw/usb-hub.c44
-rw-r--r--hw/usb-msd.c66
-rw-r--r--hw/usb-musb.c3
-rw-r--r--hw/usb-net.c66
-rw-r--r--hw/usb-ohci.c80
-rw-r--r--hw/usb-serial.c103
-rw-r--r--hw/usb-uhci.c204
-rw-r--r--hw/usb-wacom.c46
-rw-r--r--hw/usb-xhci.c2759
-rw-r--r--hw/usb.c147
-rw-r--r--hw/usb.h93
-rw-r--r--hw/versatile_pci.c58
-rw-r--r--hw/versatilepb.c23
-rw-r--r--hw/vexpress.c1
-rw-r--r--hw/vga-isa.c22
-rw-r--r--hw/vga-pci.c31
-rw-r--r--hw/vga.c397
-rw-r--r--hw/vga.h159
-rw-r--r--hw/vga_int.h16
-rw-r--r--hw/vga_template.h74
-rw-r--r--hw/vhost.c2
-rw-r--r--hw/virtex_ml507.c1
-rw-r--r--hw/virtio-blk.c2
-rw-r--r--hw/virtio-console.c77
-rw-r--r--hw/virtio-net.c2
-rw-r--r--hw/virtio-pci.c242
-rw-r--r--hw/virtio-serial-bus.c77
-rw-r--r--hw/virtio-serial.h85
-rw-r--r--hw/virtio.c12
-rw-r--r--hw/vmmouse.c36
-rw-r--r--hw/vmport.c20
-rw-r--r--hw/vmware_vga.c38
-rw-r--r--hw/vmware_vga.h8
-rw-r--r--hw/vt82c686.c136
-rw-r--r--hw/wdt_i6300esb.c37
-rw-r--r--hw/wdt_ib700.c22
-rw-r--r--hw/wm8750.c41
-rw-r--r--hw/xen_platform.c38
-rw-r--r--hw/xgmac.c433
-rw-r--r--hw/xilinx_axidma.c31
-rw-r--r--hw/xilinx_axienet.c39
-rw-r--r--hw/xilinx_ethlite.c35
-rw-r--r--hw/xilinx_intc.c29
-rw-r--r--hw/xilinx_timer.c31
-rw-r--r--hw/xilinx_uartlite.c19
-rw-r--r--hw/xio3130_downstream.c63
-rw-r--r--hw/xio3130_upstream.c57
-rw-r--r--hw/z2.c60
-rw-r--r--hw/zaurus.c31
-rw-r--r--include/qemu/object.h662
-rw-r--r--kvm-all.c168
-rw-r--r--kvm-stub.c5
-rw-r--r--kvm.h14
-rw-r--r--linux-headers/asm-powerpc/kvm.h11
-rw-r--r--linux-headers/asm-powerpc/kvm_para.h41
-rw-r--r--linux-headers/asm-s390/kvm.h9
-rw-r--r--linux-headers/asm-x86/hyperv.h1
-rw-r--r--linux-headers/asm-x86/kvm.h4
-rw-r--r--linux-headers/linux/kvm.h78
-rw-r--r--linux-headers/linux/kvm_para.h1
-rw-r--r--linux-headers/linux/virtio_ring.h6
-rw-r--r--linux-user/elfload.c15
-rw-r--r--linux-user/main.c7
-rw-r--r--linux-user/mips64/syscall.h3
-rw-r--r--linux-user/mipsn32/syscall.h3
-rw-r--r--linux-user/qemu.h3
-rw-r--r--linux-user/signal.c8
-rw-r--r--linux-user/strace.c19
-rw-r--r--linux-user/syscall.c303
-rw-r--r--linux-user/syscall_defs.h6
-rw-r--r--main-loop.c7
-rw-r--r--main-loop.h12
-rw-r--r--memory.c46
-rw-r--r--memory.h36
-rw-r--r--monitor.c192
-rw-r--r--monitor.h7
-rw-r--r--net.c36
-rw-r--r--net.h3
-rw-r--r--net/checksum.c5
-rw-r--r--net/tap.c204
-rw-r--r--net/tap.h3
-rw-r--r--os-posix.c2
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/bamboo.dtbbin3179 -> 3211 bytes
-rw-r--r--pc-bios/bamboo.dts128
-rw-r--r--pc-bios/optionrom/Makefile3
-rw-r--r--pc-bios/slof.binbin738744 -> 869584 bytes
-rw-r--r--qapi-schema.json333
-rw-r--r--qemu-bridge-helper.c410
-rw-r--r--qemu-char.c10
-rw-r--r--qemu-char.h2
-rw-r--r--qemu-common.h7
-rw-r--r--qemu-config.c4
-rw-r--r--qemu-coroutine-sleep.c38
-rw-r--r--qemu-coroutine.h9
-rw-r--r--qemu-io.c52
-rw-r--r--qemu-option.c58
-rw-r--r--qemu-option.h2
-rw-r--r--qemu-options.hx78
-rw-r--r--qemu-thread-win32.c9
-rw-r--r--qemu-timer.c29
-rw-r--r--qemu-tool.c7
-rw-r--r--qerror.c101
-rw-r--r--qerror.h86
-rw-r--r--qmp-commands.hx60
-rw-r--r--qmp.c209
-rw-r--r--qom/Makefile1
-rw-r--r--qom/container.c27
-rw-r--r--qom/object.c984
m---------roms/SLOF0
-rwxr-xr-xscripts/check-qerror.sh22
-rw-r--r--sysemu.h2
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/helper.c86
-rw-r--r--target-i386/cpuid.c14
-rw-r--r--target-i386/hyperv.c64
-rw-r--r--target-i386/hyperv.h45
-rw-r--r--target-i386/kvm.c114
-rw-r--r--target-ppc/cpu.h59
-rw-r--r--target-ppc/helper.c32
-rw-r--r--target-ppc/helper.h5
-rw-r--r--target-ppc/kvm.c10
-rw-r--r--target-ppc/op_helper.c159
-rw-r--r--target-ppc/translate.c75
-rw-r--r--target-ppc/translate_init.c64
-rw-r--r--target-sparc/vis_helper.c2
-rw-r--r--test-qmp-input-visitor.c7
-rw-r--r--tests/Makefile2
-rw-r--r--trace-events17
-rw-r--r--ui/sdl.c60
-rw-r--r--ui/vnc.c14
-rw-r--r--usb-bsd.c30
-rw-r--r--usb-linux.c510
-rw-r--r--usb-redir.c163
-rw-r--r--vl.c120
-rw-r--r--xen-all.c3
426 files changed, 22791 insertions, 8425 deletions
diff --git a/.gitignore b/.gitignore
index 406f75f2b6..f5aab2cb07 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,6 +42,10 @@ qemu-ga
qemu-monitor.texi
QMP/qmp-commands.txt
test-coroutine
+test-qmp-input-visitor
+test-qmp-output-visitor
+fsdev/virtfs-proxy-helper.1
+fsdev/virtfs-proxy-helper.pod
.gdbinit
*.a
*.aux
diff --git a/MAINTAINERS b/MAINTAINERS
index f9f131c305..173e893a62 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -93,6 +93,7 @@ F: target-mips/
PowerPC
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: target-ppc/
@@ -160,6 +161,26 @@ S: Supported
F: xen-*
F: */xen*
+Hosts:
+------
+
+LINUX
+L: qemu-devel@nongnu.org
+S: Maintained
+F: linux-*
+F: linux-headers/
+
+POSIX
+L: qemu-devel@nongnu.org
+S: Maintained
+F: *posix*
+
+W32, W64
+L: qemu-devel@nongnu.org
+M: Stefan Weil <sw@weilnetz.de>
+S: Maintained
+F: *win32*
+
ARM Machines
------------
Gumstix
@@ -290,23 +311,31 @@ PowerPC Machines
----------------
405
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc405_boards.c
New World
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc_newworld.c
+F: hw/unin_pci.c
+F: hw/dec_pci.[hc]
Old World
M: Alexander Graf <agraf@suse.de>
+L: qemu-ppc@nongnu.org
S: Maintained
F: hw/ppc_oldworld.c
+F: hw/grackle_pci.c
PReP
M: Andreas Färber <andreas.faerber@web.de>
+L: qemu-ppc@nongnu.org
S: Odd Fixes
F: hw/ppc_prep.c
+F: hw/prep_pci.[hc]
SH4 Machines
------------
diff --git a/Makefile b/Makefile
index 2bbc547108..47acf3dc36 100644
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,8 @@ $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
LIBS+=-lz $(LIBS_TOOLS)
+HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
+
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 QMP/qmp-commands.txt
DOCS+=fsdev/virtfs-proxy-helper.1
@@ -77,7 +79,7 @@ defconfig:
-include config-all-devices.mak
-build-all: $(DOCS) $(TOOLS) recurse-all
+build-all: $(DOCS) $(TOOLS) $(HELPERS-y) recurse-all
config-host.h: config-host.h-timestamp
config-host.h-timestamp: config-host.mak
@@ -114,6 +116,8 @@ QEMU_CFLAGS+=$(CURL_CFLAGS)
QEMU_CFLAGS+=$(GLIB_CFLAGS)
+QEMU_CFLAGS += -I$(SRC_PATH)/include
+
ui/cocoa.o: ui/cocoa.m
ui/sdl.o audio/sdlaudio.o ui/sdl_zoom.o baum.o: QEMU_CFLAGS += $(SDL_CFLAGS)
@@ -156,6 +160,8 @@ qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y)
qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y)
qemu-io$(EXESUF): qemu-io.o cmd.o $(tools-obj-y) $(block-obj-y)
+qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o
+
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/virtio-9p-marshal.o oslib-posix.o $(trace-obj-y)
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap
@@ -168,7 +174,9 @@ qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
gen-out-type = $(subst .,-,$(suffix $@))
+ifneq ($(wildcard config-host.mak),)
include $(SRC_PATH)/tests/Makefile
+endif
$(qapi-dir)/qga-qapi-types.c $(qapi-dir)/qga-qapi-types.h :\
$(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py
@@ -203,7 +211,7 @@ clean:
# avoid old build problems by removing potentially incorrect old files
rm -f config.mak op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
rm -f qemu-options.def
- rm -f *.o *.d *.a *.lo $(TOOLS) qemu-ga TAGS cscope.* *.pod *~ */*~
+ rm -f *.o *.d *.a *.lo $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
rm -Rf .libs
rm -f slirp/*.o slirp/*.d audio/*.o audio/*.d block/*.o block/*.d net/*.o net/*.d fsdev/*.o fsdev/*.d ui/*.o ui/*.d qapi/*.o qapi/*.d qga/*.o qga/*.d
rm -f qemu-img-cmds.h
@@ -211,6 +219,7 @@ clean:
rm -f trace.c trace.h trace.c-timestamp trace.h-timestamp
rm -f trace-dtrace.dtrace trace-dtrace.dtrace-timestamp
rm -f trace-dtrace.h trace-dtrace.h-timestamp
+ rm -f $(GENERATED_HEADERS)
rm -f $(GENERATED_SOURCES)
rm -rf $(qapi-dir)
$(MAKE) -C tests/tcg clean
@@ -228,6 +237,7 @@ distclean: clean
rm -f qemu-doc.log qemu-doc.pdf qemu-doc.pg qemu-doc.toc qemu-doc.tp
rm -f qemu-doc.vr
rm -f config.log
+ rm -f linux-headers/asm
rm -f qemu-tech.info qemu-tech.aux qemu-tech.cp qemu-tech.dvi qemu-tech.fn qemu-tech.info qemu-tech.ky qemu-tech.log qemu-tech.pdf qemu-tech.pg qemu-tech.toc qemu-tech.tp qemu-tech.vr
for d in $(TARGET_DIRS) $(QEMULIBS); do \
rm -rf $$d || exit 1 ; \
@@ -275,6 +285,10 @@ install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
ifneq ($(TOOLS),)
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
endif
+ifneq ($(HELPERS-y),)
+ $(INSTALL_DIR) "$(DESTDIR)$(libexecdir)"
+ $(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
+endif
ifneq ($(BLOBS),)
$(INSTALL_DIR) "$(DESTDIR)$(datadir)"
set -e; for x in $(BLOBS); do \
diff --git a/Makefile.hw b/Makefile.hw
index 63eb7e40be..7b8d068c94 100644
--- a/Makefile.hw
+++ b/Makefile.hw
@@ -11,6 +11,7 @@ $(call set-vpath, $(SRC_PATH):$(SRC_PATH)/hw)
QEMU_CFLAGS+=-I..
QEMU_CFLAGS += $(GLIB_CFLAGS)
+QEMU_CFLAGS += -I$(SRC_PATH)/include
include $(SRC_PATH)/Makefile.objs
diff --git a/Makefile.objs b/Makefile.objs
index 4f6d26c917..ec35320ff5 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -13,6 +13,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o
#######################################################################
# coroutines
coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
+coroutine-obj-y += qemu-coroutine-sleep.o
ifeq ($(CONFIG_UCONTEXT_COROUTINE),y)
coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o
else
@@ -34,6 +35,7 @@ block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow
block-nested-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
block-nested-y += qed-check.o
block-nested-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+block-nested-y += stream.o
block-nested-$(CONFIG_WIN32) += raw-win32.o
block-nested-$(CONFIG_POSIX) += raw-posix.o
block-nested-$(CONFIG_LIBISCSI) += iscsi.o
@@ -102,7 +104,7 @@ common-obj-y += scsi-disk.o cdrom.o
common-obj-y += scsi-generic.o scsi-bus.o
common-obj-y += hid.o
common-obj-y += usb.o usb-hub.o usb-$(HOST_USB).o usb-hid.o usb-msd.o usb-wacom.o
-common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o
+common-obj-y += usb-serial.o usb-net.o usb-bus.o usb-desc.o usb-audio.o
common-obj-$(CONFIG_SSI) += ssi.o
common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
common-obj-$(CONFIG_SD) += sd.o
@@ -111,7 +113,7 @@ common-obj-y += bt-hci-csr.o
common-obj-y += buffered_file.o migration.o migration-tcp.o
common-obj-y += qemu-char.o #aio.o
common-obj-y += msmouse.o ps2.o
-common-obj-y += qdev.o qdev-properties.o
+common-obj-y += qdev.o qdev-properties.o qdev-monitor.o
common-obj-y += block-migration.o iohandler.o
common-obj-y += pflib.o
common-obj-y += bitmap.o bitops.o
@@ -122,6 +124,9 @@ common-obj-$(CONFIG_WIN32) += version.o
common-obj-$(CONFIG_SPICE) += ui/spice-core.o ui/spice-input.o ui/spice-display.o spice-qemu-char.o
+include $(SRC_PATH)/qom/Makefile
+common-obj-y += $(addprefix qom/, $(qom-y))
+
audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o
audio-obj-$(CONFIG_SDL) += sdlaudio.o
audio-obj-$(CONFIG_OSS) += ossaudio.o
@@ -211,19 +216,22 @@ hw-obj-$(CONFIG_PCKBD) += pckbd.o
hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
+hw-obj-$(CONFIG_USB_XHCI) += usb-xhci.o
hw-obj-$(CONFIG_FDC) += fdc.o
hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
hw-obj-$(CONFIG_DMA) += dma.o
+hw-obj-$(CONFIG_I82374) += i82374.o
hw-obj-$(CONFIG_HPET) += hpet.o
hw-obj-$(CONFIG_APPLESMC) += applesmc.o
hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
-hw-obj-$(CONFIG_I8259) += i8259.o
+hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
# PPC devices
hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
+hw-obj-$(CONFIG_I82378) += i82378.o
# Mac shared devices
hw-obj-$(CONFIG_MACIO) += macio.o
hw-obj-$(CONFIG_CUDA) += cuda.o
@@ -278,7 +286,7 @@ hw-obj-$(CONFIG_LSI_SCSI_PCI) += lsi53c895a.o
hw-obj-$(CONFIG_ESP) += esp.o
hw-obj-y += dma-helpers.o sysbus.o isa-bus.o
-hw-obj-y += qdev-addr.o container.o
+hw-obj-y += qdev-addr.o
# VGA
hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o
@@ -286,6 +294,7 @@ hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o
hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o
hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o
hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o
+hw-obj-$(CONFIG_VGA_CIRRUS) += cirrus_vga.o
hw-obj-$(CONFIG_RC4030) += rc4030.o
hw-obj-$(CONFIG_DP8393X) += dp8393x.o
diff --git a/Makefile.target b/Makefile.target
index 06d79b8028..7ed497942a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -22,15 +22,24 @@ QEMU_CFLAGS += -I.. -I$(TARGET_PATH) -DNEED_CPU_H
include $(SRC_PATH)/Makefile.objs
+QEMU_CFLAGS+=-I$(SRC_PATH)/include
+
ifdef CONFIG_USER_ONLY
# user emulator name
QEMU_PROG=qemu-$(TARGET_ARCH2)
else
# system emulator name
+ifneq (,$(findstring -mwindows,$(LIBS)))
+# Terminate program name with a 'w' because the linker builds a windows executable.
+QEMU_PROGW=qemu-system-$(TARGET_ARCH2)w$(EXESUF)
+endif # windows executable
QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
endif
PROGS=$(QEMU_PROG)
+ifdef QEMU_PROGW
+PROGS+=$(QEMU_PROGW)
+endif
STPFILES=
ifndef CONFIG_HAIKU
@@ -196,9 +205,12 @@ obj-$(CONFIG_VHOST_NET) += vhost.o
obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
+obj-$(CONFIG_VGA) += vga.o
obj-y += memory.o savevm.o
LIBS+=-lz
+obj-i386-$(CONFIG_KVM) += hyperv.o
+
QEMU_CFLAGS += $(VNC_TLS_CFLAGS)
QEMU_CFLAGS += $(VNC_SASL_CFLAGS)
QEMU_CFLAGS += $(VNC_JPEG_CFLAGS)
@@ -224,19 +236,17 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
obj-y += device-hotplug.o
# Hardware support
-obj-i386-y += vga.o
obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
obj-i386-y += vmport.o
obj-i386-y += pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += debugcon.o multiboot.o
obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvmclock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
# shared objects
obj-ppc-y = ppc.o ppc_booke.o
-obj-ppc-y += vga.o
# PREP target
obj-ppc-y += mc146818rtc.o
obj-ppc-y += ppc_prep.o
@@ -250,7 +260,7 @@ obj-ppc-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o
obj-ppc-$(CONFIG_PSERIES) += spapr_pci.o device-hotplug.o pci-hotplug.o
# PowerPC 4xx boards
obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
-obj-ppc-y += ppc440.o ppc440_bamboo.o
+obj-ppc-y += ppc440_bamboo.o
# PowerPC E500 boards
obj-ppc-y += ppce500_mpc8544ds.o mpc8544_guts.o ppce500_spin.o
# PowerPC 440 Xilinx ML507 reference board.
@@ -290,10 +300,8 @@ obj-lm32-y += framebuffer.o
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-mips-y += mips_addr.o mips_timer.o mips_int.o
-obj-mips-y += vga.o
obj-mips-y += jazz_led.o
obj-mips-y += gt64xxx.o mc146818rtc.o
-obj-mips-y += cirrus_vga.o
obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o
obj-microblaze-y = petalogix_s3adsp1800_mmu.o
@@ -323,9 +331,7 @@ obj-cris-y += etraxfs_ser.o
ifeq ($(TARGET_ARCH), sparc64)
obj-sparc-y = sun4u.o apb_pci.o
-obj-sparc-y += vga.o
obj-sparc-y += mc146818rtc.o
-obj-sparc-y += cirrus_vga.o
else
obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o
obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o
@@ -342,7 +348,9 @@ obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
obj-arm-y += arm_l2x0.o
obj-arm-y += arm_mptimer.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
+obj-arm-y += highbank.o
obj-arm-y += pl061.o
+obj-arm-y += xgmac.o
obj-arm-y += arm-semi.o
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
@@ -353,7 +361,7 @@ obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \
obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \
omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o
obj-arm-y += omap_sx1.o palm.o tsc210x.o
-obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
+obj-arm-y += nseries.o blizzard.o onenand.o cbus.o tusb6010.o usb-musb.o
obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
@@ -373,7 +381,6 @@ obj-m68k-y += m68k-semi.o dummy_m68k.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
obj-alpha-y = mc146818rtc.o
-obj-alpha-y += vga.o cirrus_vga.o
obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
obj-xtensa-y += xtensa_pic.o
@@ -407,9 +414,16 @@ endif # CONFIG_LINUX_USER
obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o
+ifdef QEMU_PROGW
+# The linker builds a windows executable. Make also a console executable.
+$(QEMU_PROGW): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
+ $(call LINK,$^)
+$(QEMU_PROG): $(QEMU_PROGW)
+ $(call quiet-command,$(OBJCOPY) --subsystem console $(QEMU_PROGW) $(QEMU_PROG)," GEN $(TARGET_DIR)$(QEMU_PROG)")
+else
$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)
$(call LINK,$^)
-
+endif
gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/scripts/feature_to_c.sh
$(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/scripts/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@")
@@ -422,7 +436,7 @@ qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
clean:
rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
- rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
+ rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o kvm/*.o
rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
ifdef CONFIG_TRACE_SYSTEMTAP
rm -f *.stp
diff --git a/QMP/qmp-events.txt b/QMP/qmp-events.txt
index af586ec855..06cb404837 100644
--- a/QMP/qmp-events.txt
+++ b/QMP/qmp-events.txt
@@ -264,3 +264,56 @@ Example:
Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
followed respectively by the RESET, SHUTDOWN, or STOP events.
+
+
+BLOCK_JOB_COMPLETED
+-------------------
+
+Emitted when a block job has completed.
+
+Data:
+
+- "type": Job type ("stream" for image streaming, json-string)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+- "error": Error message (json-string, optional)
+ Only present on failure. This field contains a human-readable
+ error message. There are no semantics other than that streaming
+ has failed and clients should not try to interpret the error
+ string.
+
+Example:
+
+{ "event": "BLOCK_JOB_COMPLETED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 10737418240,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+
+
+BLOCK_JOB_CANCELLED
+-------------------
+
+Emitted when a block job has been cancelled.
+
+Data:
+
+- "type": Job type ("stream" for image streaming, json-string)
+- "device": Device name (json-string)
+- "len": Maximum progress value (json-int)
+- "offset": Current progress value (json-int)
+ On success this is equal to len.
+ On failure this is less than len.
+- "speed": Rate limit, bytes per second (json-int)
+
+Example:
+
+{ "event": "BLOCK_JOB_CANCELLED",
+ "data": { "type": "stream", "device": "virtio-disk0",
+ "len": 10737418240, "offset": 134217728,
+ "speed": 0 },
+ "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
diff --git a/arch_init.c b/arch_init.c
index 95ac682b05..699bdd1051 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -141,7 +141,8 @@ static int ram_save_block(QEMUFile *f)
do {
mr = block->mr;
- if (memory_region_get_dirty(mr, offset, DIRTY_MEMORY_MIGRATION)) {
+ if (memory_region_get_dirty(mr, offset, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_MIGRATION)) {
uint8_t *p;
int cont = (block == last_block) ? RAM_SAVE_FLAG_CONTINUE : 0;
@@ -198,7 +199,7 @@ static ram_addr_t ram_save_remaining(void)
QLIST_FOREACH(block, &ram_list.blocks, next) {
ram_addr_t addr;
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
- if (memory_region_get_dirty(block->mr, addr,
+ if (memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
count++;
}
@@ -283,9 +284,9 @@ int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
/* Make sure all dirty bits are set */
QLIST_FOREACH(block, &ram_list.blocks, next) {
for (addr = 0; addr < block->length; addr += TARGET_PAGE_SIZE) {
- if (!memory_region_get_dirty(block->mr, addr,
+ if (!memory_region_get_dirty(block->mr, addr, TARGET_PAGE_SIZE,
DIRTY_MEMORY_MIGRATION)) {
- memory_region_set_dirty(block->mr, addr);
+ memory_region_set_dirty(block->mr, addr, TARGET_PAGE_SIZE);
}
}
}
diff --git a/block.c b/block.c
index 3f072f6274..3621d11de0 100644
--- a/block.c
+++ b/block.c
@@ -48,6 +48,10 @@
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
+typedef enum {
+ BDRV_REQ_COPY_ON_READ = 0x1,
+} BdrvRequestFlags;
+
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@@ -62,7 +66,8 @@ static int coroutine_fn bdrv_co_writev_em(BlockDriverState *bs,
int64_t sector_num, int nb_sectors,
QEMUIOVector *iov);
static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+ BdrvRequestFlags flags);
static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
static BlockDriverAIOCB *bdrv_co_aio_rw_vector(BlockDriverState *bs,
@@ -1020,6 +1025,10 @@ int bdrv_commit(BlockDriverState *bs)
return -EACCES;
}
+ if (bdrv_in_use(bs) || bdrv_in_use(bs->backing_hd)) {
+ return -EBUSY;
+ }
+
backing_drv = bs->backing_hd->drv;
ro = bs->backing_hd->read_only;
strncpy(filename, bs->backing_hd->filename, sizeof(filename));
@@ -1288,7 +1297,7 @@ static void coroutine_fn bdrv_rw_co_entry(void *opaque)
if (!rwco->is_write) {
rwco->ret = bdrv_co_do_readv(rwco->bs, rwco->sector_num,
- rwco->nb_sectors, rwco->qiov);
+ rwco->nb_sectors, rwco->qiov, 0);
} else {
rwco->ret = bdrv_co_do_writev(rwco->bs, rwco->sector_num,
rwco->nb_sectors, rwco->qiov);
@@ -1496,7 +1505,7 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
return 0;
}
-static int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
{
/* Perform I/O through a temporary buffer so that users who scribble over
@@ -1519,8 +1528,8 @@ static int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
round_to_clusters(bs, sector_num, nb_sectors,
&cluster_sector_num, &cluster_nb_sectors);
- trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors,
- cluster_sector_num, cluster_nb_sectors);
+ trace_bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors,
+ cluster_sector_num, cluster_nb_sectors);
iov.iov_len = cluster_nb_sectors * BDRV_SECTOR_SIZE;
iov.iov_base = bounce_buffer = qemu_blockalign(bs, iov.iov_len);
@@ -1555,7 +1564,8 @@ err:
* Handle a read request in coroutine context
*/
static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
- int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov,
+ BdrvRequestFlags flags)
{
BlockDriver *drv = bs->drv;
BdrvTrackedRequest req;
@@ -1574,12 +1584,19 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
}
if (bs->copy_on_read) {
+ flags |= BDRV_REQ_COPY_ON_READ;
+ }
+ if (flags & BDRV_REQ_COPY_ON_READ) {
+ bs->copy_on_read_in_flight++;
+ }
+
+ if (bs->copy_on_read_in_flight) {
wait_for_overlapping_requests(bs, sector_num, nb_sectors);
}
tracked_request_begin(&req, bs, sector_num, nb_sectors, false);
- if (bs->copy_on_read) {
+ if (flags & BDRV_REQ_COPY_ON_READ) {
int pnum;
ret = bdrv_co_is_allocated(bs, sector_num, nb_sectors, &pnum);
@@ -1588,7 +1605,7 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
}
if (!ret || pnum != nb_sectors) {
- ret = bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, qiov);
+ ret = bdrv_co_do_copy_on_readv(bs, sector_num, nb_sectors, qiov);
goto out;
}
}
@@ -1597,6 +1614,11 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
out:
tracked_request_end(&req);
+
+ if (flags & BDRV_REQ_COPY_ON_READ) {
+ bs->copy_on_read_in_flight--;
+ }
+
return ret;
}
@@ -1605,7 +1627,16 @@ int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
{
trace_bdrv_co_readv(bs, sector_num, nb_sectors);
- return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov);
+ return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov, 0);
+}
+
+int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
+{
+ trace_bdrv_co_copy_on_readv(bs, sector_num, nb_sectors);
+
+ return bdrv_co_do_readv(bs, sector_num, nb_sectors, qiov,
+ BDRV_REQ_COPY_ON_READ);
}
/*
@@ -1633,7 +1664,7 @@ static int coroutine_fn bdrv_co_do_writev(BlockDriverState *bs,
bdrv_io_limits_intercept(bs, true, nb_sectors);
}
- if (bs->copy_on_read) {
+ if (bs->copy_on_read_in_flight) {
wait_for_overlapping_requests(bs, sector_num, nb_sectors);
}
@@ -2564,6 +2595,24 @@ int bdrv_snapshot_load_tmp(BlockDriverState *bs,
return -ENOTSUP;
}
+BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
+ const char *backing_file)
+{
+ if (!bs->drv) {
+ return NULL;
+ }
+
+ if (bs->backing_hd) {
+ if (strcmp(bs->backing_file, backing_file) == 0) {
+ return bs->backing_hd;
+ } else {
+ return bdrv_find_backing_image(bs->backing_hd, backing_file);
+ }
+ }
+
+ return NULL;
+}
+
#define NB_SUFFIXES 4
char *get_human_readable_size(char *buf, int buf_size, int64_t size)
@@ -3140,7 +3189,7 @@ static void coroutine_fn bdrv_co_do_rw(void *opaque)
if (!acb->is_write) {
acb->req.error = bdrv_co_do_readv(bs, acb->req.sector,
- acb->req.nb_sectors, acb->req.qiov);
+ acb->req.nb_sectors, acb->req.qiov, 0);
} else {
acb->req.error = bdrv_co_do_writev(bs, acb->req.sector,
acb->req.nb_sectors, acb->req.qiov);
@@ -3827,3 +3876,51 @@ out:
return ret;
}
+
+void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BlockJob *job;
+
+ if (bs->job || bdrv_in_use(bs)) {
+ return NULL;
+ }
+ bdrv_set_in_use(bs, 1);
+
+ job = g_malloc0(job_type->instance_size);
+ job->job_type = job_type;
+ job->bs = bs;
+ job->cb = cb;
+ job->opaque = opaque;
+ bs->job = job;
+ return job;
+}
+
+void block_job_complete(BlockJob *job, int ret)
+{
+ BlockDriverState *bs = job->bs;
+
+ assert(bs->job == job);
+ job->cb(job->opaque, ret);
+ bs->job = NULL;
+ g_free(job);
+ bdrv_set_in_use(bs, 0);
+}
+
+int block_job_set_speed(BlockJob *job, int64_t value)
+{
+ if (!job->job_type->set_speed) {
+ return -ENOTSUP;
+ }
+ return job->job_type->set_speed(job, value);
+}
+
+void block_job_cancel(BlockJob *job)
+{
+ job->cancelled = true;
+}
+
+bool block_job_is_cancelled(BlockJob *job)
+{
+ return job->cancelled;
+}
diff --git a/block.h b/block.h
index 3bd4398609..cae289b2fb 100644
--- a/block.h
+++ b/block.h
@@ -142,10 +142,14 @@ int bdrv_pwrite_sync(BlockDriverState *bs, int64_t offset,
const void *buf, int count);
int coroutine_fn bdrv_co_readv(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov);
+int coroutine_fn bdrv_co_copy_on_readv(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn bdrv_co_writev(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t sector_num,
int nb_sectors, int *pnum);
+BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
+ const char *backing_file);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 9b885359e4..a251802ad4 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -292,10 +292,10 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags)
return -EINVAL;
}
- config = strdup(filename);
+ config = g_strdup(filename);
config[c - filename] = '\0';
ret = read_config(s, config);
- free(config);
+ g_free(config);
if (ret < 0) {
return ret;
}
diff --git a/block/blkverify.c b/block/blkverify.c
index 4ca8584b88..9d5f1ec5b9 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -87,10 +87,10 @@ static int blkverify_open(BlockDriverState *bs, const char *filename, int flags)
return -EINVAL;
}
- raw = strdup(filename);
+ raw = g_strdup(filename);
raw[c - filename] = '\0';
ret = bdrv_file_open(&bs->file, raw, flags);
- free(raw);
+ g_free(raw);
if (ret < 0) {
return ret;
}
diff --git a/block/qcow.c b/block/qcow.c
index b16955d764..b1cfe1f696 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -95,11 +95,13 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
static int qcow_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
- int len, i, shift;
+ int len, i, shift, ret;
QCowHeader header;
- if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header))
+ ret = bdrv_pread(bs->file, 0, &header, sizeof(header));
+ if (ret < 0) {
goto fail;
+ }
be32_to_cpus(&header.magic);
be32_to_cpus(&header.version);
be64_to_cpus(&header.backing_file_offset);
@@ -109,15 +111,31 @@ static int qcow_open(BlockDriverState *bs, int flags)
be32_to_cpus(&header.crypt_method);
be64_to_cpus(&header.l1_table_offset);
- if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
+ if (header.magic != QCOW_MAGIC) {
+ ret = -EINVAL;
goto fail;
- if (header.size <= 1 || header.cluster_bits < 9)
+ }
+ if (header.version != QCOW_VERSION) {
+ char version[64];
+ snprintf(version, sizeof(version), "QCOW version %d", header.version);
+ qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+ bs->device_name, "qcow", version);
+ ret = -ENOTSUP;
goto fail;
- if (header.crypt_method > QCOW_CRYPT_AES)
+ }
+
+ if (header.size <= 1 || header.cluster_bits < 9) {
+ ret = -EINVAL;
+ goto fail;
+ }
+ if (header.crypt_method > QCOW_CRYPT_AES) {
+ ret = -EINVAL;
goto fail;
+ }
s->crypt_method_header = header.crypt_method;
- if (s->crypt_method_header)
+ if (s->crypt_method_header) {
bs->encrypted = 1;
+ }
s->cluster_bits = header.cluster_bits;
s->cluster_size = 1 << s->cluster_bits;
s->cluster_sectors = 1 << (s->cluster_bits - 9);
@@ -132,33 +150,33 @@ static int qcow_open(BlockDriverState *bs, int flags)
s->l1_table_offset = header.l1_table_offset;
s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
- if (!s->l1_table)
- goto fail;
- if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
- s->l1_size * sizeof(uint64_t))
+
+ ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
+ s->l1_size * sizeof(uint64_t));
+ if (ret < 0) {
goto fail;
+ }
+
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
/* alloc L2 cache */
s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
- if (!s->l2_cache)
- goto fail;
s->cluster_cache = g_malloc(s->cluster_size);
- if (!s->cluster_cache)
- goto fail;
s->cluster_data = g_malloc(s->cluster_size);
- if (!s->cluster_data)
- goto fail;
s->cluster_cache_offset = -1;
/* read the backing file name */
if (header.backing_file_offset != 0) {
len = header.backing_file_size;
- if (len > 1023)
+ if (len > 1023) {
len = 1023;
- if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len)
+ }
+ ret = bdrv_pread(bs->file, header.backing_file_offset,
+ bs->backing_file, len);
+ if (ret < 0) {
goto fail;
+ }
bs->backing_file[len] = '\0';
}
@@ -176,7 +194,7 @@ static int qcow_open(BlockDriverState *bs, int flags)
g_free(s->l2_cache);
g_free(s->cluster_cache);
g_free(s->cluster_data);
- return -1;
+ return ret;
}
static int qcow_set_key(BlockDriverState *bs, const char *key)
@@ -626,13 +644,14 @@ static void qcow_close(BlockDriverState *bs)
static int qcow_create(const char *filename, QEMUOptionParameter *options)
{
- int fd, header_size, backing_filename_len, l1_size, i, shift;
+ int header_size, backing_filename_len, l1_size, shift, i;
QCowHeader header;
- uint64_t tmp;
+ uint8_t *tmp;
int64_t total_size = 0;
const char *backing_file = NULL;
int flags = 0;
int ret;
+ BlockDriverState *qcow_bs;
/* Read out options */
while (options && options->name) {
@@ -646,9 +665,21 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
options++;
}
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (fd < 0)
- return -errno;
+ ret = bdrv_create_file(filename, options);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = bdrv_file_open(&qcow_bs, filename, BDRV_O_RDWR);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = bdrv_truncate(qcow_bs, 0);
+ if (ret < 0) {
+ goto exit;
+ }
+
memset(&header, 0, sizeof(header));
header.magic = cpu_to_be32(QCOW_MAGIC);
header.version = cpu_to_be32(QCOW_VERSION);
@@ -684,33 +715,34 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
}
/* write all the data */
- ret = qemu_write_full(fd, &header, sizeof(header));
+ ret = bdrv_pwrite(qcow_bs, 0, &header, sizeof(header));
if (ret != sizeof(header)) {
- ret = -errno;
goto exit;
}
if (backing_file) {
- ret = qemu_write_full(fd, backing_file, backing_filename_len);
+ ret = bdrv_pwrite(qcow_bs, sizeof(header),
+ backing_file, backing_filename_len);
if (ret != backing_filename_len) {
- ret = -errno;
goto exit;
}
-
}
- lseek(fd, header_size, SEEK_SET);
- tmp = 0;
- for(i = 0;i < l1_size; i++) {
- ret = qemu_write_full(fd, &tmp, sizeof(tmp));
- if (ret != sizeof(tmp)) {
- ret = -errno;
+
+ tmp = g_malloc0(BDRV_SECTOR_SIZE);
+ for (i = 0; i < ((sizeof(uint64_t)*l1_size + BDRV_SECTOR_SIZE - 1)/
+ BDRV_SECTOR_SIZE); i++) {
+ ret = bdrv_pwrite(qcow_bs, header_size +
+ BDRV_SECTOR_SIZE*i, tmp, BDRV_SECTOR_SIZE);
+ if (ret != BDRV_SECTOR_SIZE) {
+ g_free(tmp);
goto exit;
}
}
+ g_free(tmp);
ret = 0;
exit:
- close(fd);
+ bdrv_delete(qcow_bs);
return ret;
}
diff --git a/block/rbd.c b/block/rbd.c
index db5abf240b..46a8579018 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -789,6 +789,26 @@ static int qemu_rbd_snap_create(BlockDriverState *bs,
return 0;
}
+static int qemu_rbd_snap_remove(BlockDriverState *bs,
+ const char *snapshot_name)
+{
+ BDRVRBDState *s = bs->opaque;
+ int r;
+
+ r = rbd_snap_remove(s->image, snapshot_name);
+ return r;
+}
+
+static int qemu_rbd_snap_rollback(BlockDriverState *bs,
+ const char *snapshot_name)
+{
+ BDRVRBDState *s = bs->opaque;
+ int r;
+
+ r = rbd_snap_rollback(s->image, snapshot_name);
+ return r;
+}
+
static int qemu_rbd_snap_list(BlockDriverState *bs,
QEMUSnapshotInfo **psn_tab)
{
@@ -862,7 +882,9 @@ static BlockDriver bdrv_rbd = {
.bdrv_co_flush_to_disk = qemu_rbd_co_flush,
.bdrv_snapshot_create = qemu_rbd_snap_create,
+ .bdrv_snapshot_delete = qemu_rbd_snap_remove,
.bdrv_snapshot_list = qemu_rbd_snap_list,
+ .bdrv_snapshot_goto = qemu_rbd_snap_rollback,
};
static void bdrv_rbd_init(void)
diff --git a/block/stream.c b/block/stream.c
new file mode 100644
index 0000000000..d1b3986a8a
--- /dev/null
+++ b/block/stream.c
@@ -0,0 +1,269 @@
+/*
+ * Image streaming
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "trace.h"
+#include "block_int.h"
+
+enum {
+ /*
+ * Size of data buffer for populating the image file. This should be large
+ * enough to process multiple clusters in a single call, so that populating
+ * contiguous regions of the image is efficient.
+ */
+ STREAM_BUFFER_SIZE = 512 * 1024, /* in bytes */
+};
+
+#define SLICE_TIME 100000000ULL /* ns */
+
+typedef struct {
+ int64_t next_slice_time;
+ uint64_t slice_quota;
+ uint64_t dispatched;
+} RateLimit;
+
+static int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
+{
+ int64_t delay_ns = 0;
+ int64_t now = qemu_get_clock_ns(rt_clock);
+
+ if (limit->next_slice_time < now) {
+ limit->next_slice_time = now + SLICE_TIME;
+ limit->dispatched = 0;
+ }
+ if (limit->dispatched + n > limit->slice_quota) {
+ delay_ns = limit->next_slice_time - now;
+ } else {
+ limit->dispatched += n;
+ }
+ return delay_ns;
+}
+
+static void ratelimit_set_speed(RateLimit *limit, uint64_t speed)
+{
+ limit->slice_quota = speed / (1000000000ULL / SLICE_TIME);
+}
+
+typedef struct StreamBlockJob {
+ BlockJob common;
+ RateLimit limit;
+ BlockDriverState *base;
+ char backing_file_id[1024];
+} StreamBlockJob;
+
+static int coroutine_fn stream_populate(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors,
+ void *buf)
+{
+ struct iovec iov = {
+ .iov_base = buf,
+ .iov_len = nb_sectors * BDRV_SECTOR_SIZE,
+ };
+ QEMUIOVector qiov;
+
+ qemu_iovec_init_external(&qiov, &iov, 1);
+
+ /* Copy-on-read the unallocated clusters */
+ return bdrv_co_copy_on_readv(bs, sector_num, nb_sectors, &qiov);
+}
+
+/*
+ * Given an image chain: [BASE] -> [INTER1] -> [INTER2] -> [TOP]
+ *
+ * Return true if the given sector is allocated in top.
+ * Return false if the given sector is allocated in intermediate images.
+ * Return true otherwise.
+ *
+ * 'pnum' is set to the number of sectors (including and immediately following
+ * the specified sector) that are known to be in the same
+ * allocated/unallocated state.
+ *
+ */
+static int coroutine_fn is_allocated_base(BlockDriverState *top,
+ BlockDriverState *base,
+ int64_t sector_num,
+ int nb_sectors, int *pnum)
+{
+ BlockDriverState *intermediate;
+ int ret, n;
+
+ ret = bdrv_co_is_allocated(top, sector_num, nb_sectors, &n);
+ if (ret) {
+ *pnum = n;
+ return ret;
+ }
+
+ /*
+ * Is the unallocated chunk [sector_num, n] also
+ * unallocated between base and top?
+ */
+ intermediate = top->backing_hd;
+
+ while (intermediate) {
+ int pnum_inter;
+
+ /* reached base */
+ if (intermediate == base) {
+ *pnum = n;
+ return 1;
+ }
+ ret = bdrv_co_is_allocated(intermediate, sector_num, nb_sectors,
+ &pnum_inter);
+ if (ret < 0) {
+ return ret;
+ } else if (ret) {
+ *pnum = pnum_inter;
+ return 0;
+ }
+
+ /*
+ * [sector_num, nb_sectors] is unallocated on top but intermediate
+ * might have
+ *
+ * [sector_num+x, nr_sectors] allocated.
+ */
+ if (n > pnum_inter) {
+ n = pnum_inter;
+ }
+
+ intermediate = intermediate->backing_hd;
+ }
+
+ return 1;
+}
+
+static void coroutine_fn stream_run(void *opaque)
+{
+ StreamBlockJob *s = opaque;
+ BlockDriverState *bs = s->common.bs;
+ BlockDriverState *base = s->base;
+ int64_t sector_num, end;
+ int ret = 0;
+ int n;
+ void *buf;
+
+ s->common.len = bdrv_getlength(bs);
+ if (s->common.len < 0) {
+ block_job_complete(&s->common, s->common.len);
+ return;
+ }
+
+ end = s->common.len >> BDRV_SECTOR_BITS;
+ buf = qemu_blockalign(bs, STREAM_BUFFER_SIZE);
+
+ /* Turn on copy-on-read for the whole block device so that guest read
+ * requests help us make progress. Only do this when copying the entire
+ * backing chain since the copy-on-read operation does not take base into
+ * account.
+ */
+ if (!base) {
+ bdrv_enable_copy_on_read(bs);
+ }
+
+ for (sector_num = 0; sector_num < end; sector_num += n) {
+retry:
+ if (block_job_is_cancelled(&s->common)) {
+ break;
+ }
+
+
+ if (base) {
+ ret = is_allocated_base(bs, base, sector_num,
+ STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
+ } else {
+ ret = bdrv_co_is_allocated(bs, sector_num,
+ STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE,
+ &n);
+ }
+ trace_stream_one_iteration(s, sector_num, n, ret);
+ if (ret == 0) {
+ if (s->common.speed) {
+ uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
+ if (delay_ns > 0) {
+ co_sleep_ns(rt_clock, delay_ns);
+
+ /* Recheck cancellation and that sectors are unallocated */
+ goto retry;
+ }
+ }
+ ret = stream_populate(bs, sector_num, n, buf);
+ }
+ if (ret < 0) {
+ break;
+ }
+ ret = 0;
+
+ /* Publish progress */
+ s->common.offset += n * BDRV_SECTOR_SIZE;
+
+ /* Note that even when no rate limit is applied we need to yield
+ * with no pending I/O here so that qemu_aio_flush() returns.
+ */
+ co_sleep_ns(rt_clock, 0);
+ }
+
+ if (!base) {
+ bdrv_disable_copy_on_read(bs);
+ }
+
+ if (sector_num == end && ret == 0) {
+ const char *base_id = NULL;
+ if (base) {
+ base_id = s->backing_file_id;
+ }
+ ret = bdrv_change_backing_file(bs, base_id, NULL);
+ }
+
+ qemu_vfree(buf);
+ block_job_complete(&s->common, ret);
+}
+
+static int stream_set_speed(BlockJob *job, int64_t value)
+{
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common);
+
+ if (value < 0) {
+ return -EINVAL;
+ }
+ job->speed = value;
+ ratelimit_set_speed(&s->limit, value / BDRV_SECTOR_SIZE);
+ return 0;
+}
+
+static BlockJobType stream_job_type = {
+ .instance_size = sizeof(StreamBlockJob),
+ .job_type = "stream",
+ .set_speed = stream_set_speed,
+};
+
+int stream_start(BlockDriverState *bs, BlockDriverState *base,
+ const char *base_id, BlockDriverCompletionFunc *cb,
+ void *opaque)
+{
+ StreamBlockJob *s;
+ Coroutine *co;
+
+ s = block_job_create(&stream_job_type, bs, cb, opaque);
+ if (!s) {
+ return -EBUSY; /* bs must already be in use */
+ }
+
+ s->base = base;
+ if (base_id) {
+ pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
+ }
+
+ co = qemu_coroutine_create(stream_run);
+ trace_stream_start(bs, base, s, co, opaque);
+ qemu_coroutine_enter(co, s);
+ return 0;
+}
diff --git a/block/vdi.c b/block/vdi.c
index 31cdfabdea..6a0011fbcc 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -1,7 +1,7 @@
/*
* Block driver for the Virtual Disk Image (VDI) format
*
- * Copyright (c) 2009 Stefan Weil
+ * Copyright (c) 2009, 2012 Stefan Weil
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -756,15 +756,19 @@ static void vdi_aio_write_cb(void *opaque, int ret)
(uint64_t)bmap_entry * s->block_sectors;
block = acb->block_buffer;
if (block == NULL) {
- block = g_malloc0(s->block_size);
+ block = g_malloc(s->block_size);
acb->block_buffer = block;
acb->bmap_first = block_index;
assert(!acb->header_modified);
acb->header_modified = 1;
}
acb->bmap_last = block_index;
+ /* Copy data to be written to new block and zero unused parts. */
+ memset(block, 0, sector_in_block * SECTOR_SIZE);
memcpy(block + sector_in_block * SECTOR_SIZE,
acb->buf, n_sectors * SECTOR_SIZE);
+ memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
+ (s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
acb->hd_iov.iov_base = (void *)block;
acb->hd_iov.iov_len = s->block_size;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
diff --git a/block_int.h b/block_int.h
index 311bd2a6fa..7be2988ca7 100644
--- a/block_int.h
+++ b/block_int.h
@@ -69,6 +69,36 @@ typedef struct BlockIOBaseValue {
uint64_t ios[2];
} BlockIOBaseValue;
+typedef void BlockJobCancelFunc(void *opaque);
+typedef struct BlockJob BlockJob;
+typedef struct BlockJobType {
+ /** Derived BlockJob struct size */
+ size_t instance_size;
+
+ /** String describing the operation, part of query-block-jobs QMP API */
+ const char *job_type;
+
+ /** Optional callback for job types that support setting a speed limit */
+ int (*set_speed)(BlockJob *job, int64_t value);
+} BlockJobType;
+
+/**
+ * Long-running operation on a BlockDriverState
+ */
+struct BlockJob {
+ const BlockJobType *job_type;
+ BlockDriverState *bs;
+ bool cancelled;
+
+ /* These fields are published by the query-block-jobs QMP API */
+ int64_t offset;
+ int64_t len;
+ int64_t speed;
+
+ BlockDriverCompletionFunc *cb;
+ void *opaque;
+};
+
struct BlockDriver {
const char *format_name;
int instance_size;
@@ -218,6 +248,9 @@ struct BlockDriverState {
BlockDriverState *backing_hd;
BlockDriverState *file;
+ /* number of in-flight copy-on-read requests */
+ unsigned int copy_on_read_in_flight;
+
/* async read/write emulation */
void *sync_aiocb;
@@ -261,6 +294,9 @@ struct BlockDriverState {
void *private;
QLIST_HEAD(, BdrvTrackedRequest) tracked_requests;
+
+ /* long-running background operation */
+ BlockJob *job;
};
struct BlockDriverAIOCB {
@@ -284,4 +320,15 @@ void bdrv_set_io_limits(BlockDriverState *bs,
int is_windows_drive(const char *filename);
#endif
+void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque);
+void block_job_complete(BlockJob *job, int ret);
+int block_job_set_speed(BlockJob *job, int64_t value);
+void block_job_cancel(BlockJob *job);
+bool block_job_is_cancelled(BlockJob *job);
+
+int stream_start(BlockDriverState *bs, BlockDriverState *base,
+ const char *base_id, BlockDriverCompletionFunc *cb,
+ void *opaque);
+
#endif /* BLOCK_INT_H */
diff --git a/blockdev.c b/blockdev.c
index c832782d03..7a6613a2d2 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -13,9 +13,12 @@
#include "qerror.h"
#include "qemu-option.h"
#include "qemu-config.h"
+#include "qemu-objects.h"
#include "sysemu.h"
#include "block_int.h"
#include "qmp-commands.h"
+#include "trace.h"
+#include "arch_init.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -200,6 +203,37 @@ void drive_get_ref(DriveInfo *dinfo)
dinfo->refcount++;
}
+typedef struct {
+ QEMUBH *bh;
+ DriveInfo *dinfo;
+} DrivePutRefBH;
+
+static void drive_put_ref_bh(void *opaque)
+{
+ DrivePutRefBH *s = opaque;
+
+ drive_put_ref(s->dinfo);
+ qemu_bh_delete(s->bh);
+ g_free(s);
+}
+
+/*
+ * Release a drive reference in a BH
+ *
+ * It is not possible to use drive_put_ref() from a callback function when the
+ * callers still need the drive. In such cases we schedule a BH to release the
+ * reference.
+ */
+static void drive_put_ref_bh_schedule(DriveInfo *dinfo)
+{
+ DrivePutRefBH *s;
+
+ s = g_new(DrivePutRefBH, 1);
+ s->bh = qemu_bh_new(drive_put_ref_bh, s);
+ s->dinfo = dinfo;
+ qemu_bh_schedule(s->bh);
+}
+
static int parse_block_error_action(const char *buf, int is_read)
{
if (!strcmp(buf, "ignore")) {
@@ -532,7 +566,11 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
case IF_VIRTIO:
/* add virtio block device */
opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
- qemu_opt_set(opts, "driver", "virtio-blk");
+ if (arch_type == QEMU_ARCH_S390X) {
+ qemu_opt_set(opts, "driver", "virtio-blk-s390");
+ } else {
+ qemu_opt_set(opts, "driver", "virtio-blk-pci");
+ }
qemu_opt_set(opts, "drive", dinfo->id);
if (devaddr)
qemu_opt_set(opts, "addr", devaddr);
@@ -592,12 +630,18 @@ void do_commit(Monitor *mon, const QDict *qdict)
if (!strcmp(device, "all")) {
bdrv_commit_all();
} else {
+ int ret;
+
bs = bdrv_find(device);
if (!bs) {
qerror_report(QERR_DEVICE_NOT_FOUND, device);
return;
}
- bdrv_commit(bs);
+ ret = bdrv_commit(bs);
+ if (ret == -EBUSY) {
+ qerror_report(QERR_DEVICE_IN_USE, device);
+ return;
+ }
}
}
@@ -616,6 +660,10 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
+ if (bdrv_in_use(bs)) {
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ return;
+ }
pstrcpy(old_filename, sizeof(old_filename), bs->filename);
@@ -665,35 +713,39 @@ void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
}
}
-static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
+static void eject_device(BlockDriverState *bs, int force, Error **errp)
{
+ if (bdrv_in_use(bs)) {
+ error_set(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
+ return;
+ }
if (!bdrv_dev_has_removable_media(bs)) {
- qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
+ return;
}
+
if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
bdrv_dev_eject_request(bs, force);
if (!force) {
- qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
- return -1;
+ error_set(errp, QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+ return;
}
}
+
bdrv_close(bs);
- return 0;
}
-int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
{
BlockDriverState *bs;
- int force = qdict_get_try_bool(qdict, "force", 0);
- const char *filename = qdict_get_str(qdict, "device");
- bs = bdrv_find(filename);
+ bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, filename);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- return eject_device(mon, bs, force);
+
+ eject_device(bs, force, errp);
}
void qmp_block_passwd(const char *device, const char *password, Error **errp)
@@ -717,78 +769,87 @@ void qmp_block_passwd(const char *device, const char *password, Error **errp)
}
}
-int do_change_block(Monitor *mon, const char *device,
- const char *filename, const char *fmt)
+static void qmp_bdrv_open_encrypted(BlockDriverState *bs, const char *filename,
+ int bdrv_flags, BlockDriver *drv,
+ const char *password, Error **errp)
+{
+ if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+ return;
+ }
+
+ if (bdrv_key_required(bs)) {
+ if (password) {
+ if (bdrv_set_key(bs, password) < 0) {
+ error_set(errp, QERR_INVALID_PASSWORD);
+ }
+ } else {
+ error_set(errp, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+ bdrv_get_encrypted_filename(bs));
+ }
+ } else if (password) {
+ error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
+ }
+}
+
+void qmp_change_blockdev(const char *device, const char *filename,
+ bool has_format, const char *format, Error **errp)
{
BlockDriverState *bs;
BlockDriver *drv = NULL;
int bdrv_flags;
+ Error *err = NULL;
bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, device);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- if (fmt) {
- drv = bdrv_find_whitelisted_format(fmt);
+
+ if (format) {
+ drv = bdrv_find_whitelisted_format(format);
if (!drv) {
- qerror_report(QERR_INVALID_BLOCK_FORMAT, fmt);
- return -1;
+ error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+ return;
}
}
- if (eject_device(mon, bs, 0) < 0) {
- return -1;
+
+ eject_device(bs, 0, &err);
+ if (error_is_set(&err)) {
+ error_propagate(errp, err);
+ return;
}
+
bdrv_flags = bdrv_is_read_only(bs) ? 0 : BDRV_O_RDWR;
bdrv_flags |= bdrv_is_snapshot(bs) ? BDRV_O_SNAPSHOT : 0;
- if (bdrv_open(bs, filename, bdrv_flags, drv) < 0) {
- qerror_report(QERR_OPEN_FILE_FAILED, filename);
- return -1;
- }
- return monitor_read_bdrv_key_start(mon, bs, NULL, NULL);
+
+ qmp_bdrv_open_encrypted(bs, filename, bdrv_flags, drv, NULL, errp);
}
/* throttling disk I/O limits */
-int do_block_set_io_throttle(Monitor *mon,
- const QDict *qdict, QObject **ret_data)
+void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
+ int64_t bps_wr, int64_t iops, int64_t iops_rd,
+ int64_t iops_wr, Error **errp)
{
BlockIOLimit io_limits;
- const char *devname = qdict_get_str(qdict, "device");
BlockDriverState *bs;
- io_limits.bps[BLOCK_IO_LIMIT_TOTAL]
- = qdict_get_try_int(qdict, "bps", -1);
- io_limits.bps[BLOCK_IO_LIMIT_READ]
- = qdict_get_try_int(qdict, "bps_rd", -1);
- io_limits.bps[BLOCK_IO_LIMIT_WRITE]
- = qdict_get_try_int(qdict, "bps_wr", -1);
- io_limits.iops[BLOCK_IO_LIMIT_TOTAL]
- = qdict_get_try_int(qdict, "iops", -1);
- io_limits.iops[BLOCK_IO_LIMIT_READ]
- = qdict_get_try_int(qdict, "iops_rd", -1);
- io_limits.iops[BLOCK_IO_LIMIT_WRITE]
- = qdict_get_try_int(qdict, "iops_wr", -1);
-
- bs = bdrv_find(devname);
+ bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, devname);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- if ((io_limits.bps[BLOCK_IO_LIMIT_TOTAL] == -1)
- || (io_limits.bps[BLOCK_IO_LIMIT_READ] == -1)
- || (io_limits.bps[BLOCK_IO_LIMIT_WRITE] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_TOTAL] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_READ] == -1)
- || (io_limits.iops[BLOCK_IO_LIMIT_WRITE] == -1)) {
- qerror_report(QERR_MISSING_PARAMETER,
- "bps/bps_rd/bps_wr/iops/iops_rd/iops_wr");
- return -1;
- }
+ io_limits.bps[BLOCK_IO_LIMIT_TOTAL] = bps;
+ io_limits.bps[BLOCK_IO_LIMIT_READ] = bps_rd;
+ io_limits.bps[BLOCK_IO_LIMIT_WRITE] = bps_wr;
+ io_limits.iops[BLOCK_IO_LIMIT_TOTAL]= iops;
+ io_limits.iops[BLOCK_IO_LIMIT_READ] = iops_rd;
+ io_limits.iops[BLOCK_IO_LIMIT_WRITE]= iops_wr;
if (!do_check_io_limits(&io_limits)) {
- qerror_report(QERR_INVALID_PARAMETER_COMBINATION);
- return -1;
+ error_set(errp, QERR_INVALID_PARAMETER_COMBINATION);
+ return;
}
bs->io_limits = io_limits;
@@ -803,8 +864,6 @@ int do_block_set_io_throttle(Monitor *mon,
qemu_mod_timer(bs->block_timer, qemu_get_clock_ns(vm_clock));
}
}
-
- return 0;
}
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
@@ -841,11 +900,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
return 0;
}
-/*
- * XXX: replace the QERR_UNDEFINED_ERROR errors with real values once the
- * existing QERR_ macro mess is cleaned up. A good example for better
- * error reports can be found in the qemu-img resize code.
- */
void qmp_block_resize(const char *device, int64_t size, Error **errp)
{
BlockDriverState *bs;
@@ -857,12 +911,177 @@ void qmp_block_resize(const char *device, int64_t size, Error **errp)
}
if (size < 0) {
- error_set(errp, QERR_UNDEFINED_ERROR);
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
return;
}
- if (bdrv_truncate(bs, size)) {
+ switch (bdrv_truncate(bs, size)) {
+ case 0:
+ break;
+ case -ENOMEDIUM:
+ error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
+ break;
+ case -ENOTSUP:
+ error_set(errp, QERR_UNSUPPORTED);
+ break;
+ case -EACCES:
+ error_set(errp, QERR_DEVICE_IS_READ_ONLY, device);
+ break;
+ case -EBUSY:
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ break;
+ default:
error_set(errp, QERR_UNDEFINED_ERROR);
+ break;
+ }
+}
+
+static QObject *qobject_from_block_job(BlockJob *job)
+{
+ return qobject_from_jsonf("{ 'type': %s,"
+ "'device': %s,"
+ "'len': %" PRId64 ","
+ "'offset': %" PRId64 ","
+ "'speed': %" PRId64 " }",
+ job->job_type->job_type,
+ bdrv_get_device_name(job->bs),
+ job->len,
+ job->offset,
+ job->speed);
+}
+
+static void block_stream_cb(void *opaque, int ret)
+{
+ BlockDriverState *bs = opaque;
+ QObject *obj;
+
+ trace_block_stream_cb(bs, bs->job, ret);
+
+ assert(bs->job);
+ obj = qobject_from_block_job(bs->job);
+ if (ret < 0) {
+ QDict *dict = qobject_to_qdict(obj);
+ qdict_put(dict, "error", qstring_from_str(strerror(-ret)));
+ }
+
+ if (block_job_is_cancelled(bs->job)) {
+ monitor_protocol_event(QEVENT_BLOCK_JOB_CANCELLED, obj);
+ } else {
+ monitor_protocol_event(QEVENT_BLOCK_JOB_COMPLETED, obj);
+ }
+ qobject_decref(obj);
+
+ drive_put_ref_bh_schedule(drive_get_by_blockdev(bs));
+}
+
+void qmp_block_stream(const char *device, bool has_base,
+ const char *base, Error **errp)
+{
+ BlockDriverState *bs;
+ BlockDriverState *base_bs = NULL;
+ int ret;
+
+ bs = bdrv_find(device);
+ if (!bs) {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return;
}
+
+ if (base) {
+ base_bs = bdrv_find_backing_image(bs, base);
+ if (base_bs == NULL) {
+ error_set(errp, QERR_BASE_NOT_FOUND, base);
+ return;
+ }
+ }
+
+ ret = stream_start(bs, base_bs, base, block_stream_cb, bs);
+ if (ret < 0) {
+ switch (ret) {
+ case -EBUSY:
+ error_set(errp, QERR_DEVICE_IN_USE, device);
+ return;
+ default:
+ error_set(errp, QERR_NOT_SUPPORTED);
+ return;
+ }
+ }
+
+ /* Grab a reference so hotplug does not delete the BlockDriverState from
+ * underneath us.
+ */
+ drive_get_ref(drive_get_by_blockdev(bs));
+
+ trace_qmp_block_stream(bs, bs->job);
+}
+
+static BlockJob *find_block_job(const char *device)
+{
+ BlockDriverState *bs;
+
+ bs = bdrv_find(device);
+ if (!bs || !bs->job) {
+ return NULL;
+ }
+ return bs->job;
+}
+
+void qmp_block_job_set_speed(const char *device, int64_t value, Error **errp)
+{
+ BlockJob *job = find_block_job(device);
+
+ if (!job) {
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
+ return;
+ }
+
+ if (block_job_set_speed(job, value) < 0) {
+ error_set(errp, QERR_NOT_SUPPORTED);
+ }
+}
+
+void qmp_block_job_cancel(const char *device, Error **errp)
+{
+ BlockJob *job = find_block_job(device);
+
+ if (!job) {
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, device);
+ return;
+ }
+
+ trace_qmp_block_job_cancel(job);
+ block_job_cancel(job);
+}
+
+static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
+{
+ BlockJobInfoList **prev = opaque;
+ BlockJob *job = bs->job;
+
+ if (job) {
+ BlockJobInfoList *elem;
+ BlockJobInfo *info = g_new(BlockJobInfo, 1);
+ *info = (BlockJobInfo){
+ .type = g_strdup(job->job_type->job_type),
+ .device = g_strdup(bdrv_get_device_name(bs)),
+ .len = job->len,
+ .offset = job->offset,
+ .speed = job->speed,
+ };
+
+ elem = g_new0(BlockJobInfoList, 1);
+ elem->value = info;
+
+ (*prev)->next = elem;
+ *prev = elem;
+ }
+}
+
+BlockJobInfoList *qmp_query_block_jobs(Error **errp)
+{
+ /* Dummy is a fake list element for holding the head pointer */
+ BlockJobInfoList dummy = {};
+ BlockJobInfoList *prev = &dummy;
+ bdrv_iterate(do_qmp_query_block_jobs_one, &prev);
+ return dummy.next;
}
diff --git a/blockdev.h b/blockdev.h
index f1b639660d..260e16b3c6 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -11,6 +11,7 @@
#define BLOCKDEV_H
#include "block.h"
+#include "error.h"
#include "qemu-queue.h"
void blockdev_mark_auto_del(BlockDriverState *bs);
@@ -57,11 +58,8 @@ DriveInfo *drive_init(QemuOpts *arg, int default_to_scsi);
DriveInfo *add_init_drive(const char *opts);
+void qmp_change_blockdev(const char *device, const char *filename,
+ bool has_format, const char *format, Error **errp);
void do_commit(Monitor *mon, const QDict *qdict);
-int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_change_block(Monitor *mon, const char *device,
- const char *filename, const char *fmt);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_block_set_io_throttle(Monitor *mon,
- const QDict *qdict, QObject **ret_data);
#endif
diff --git a/configure b/configure
index 467e87bf09..763db24cd0 100755
--- a/configure
+++ b/configure
@@ -133,6 +133,7 @@ vnc_thread="no"
xen=""
xen_ctrl_version=""
linux_aio=""
+cap_ng=""
attr=""
libattr=""
xfs=""
@@ -234,7 +235,11 @@ ld="${LD-${cross_prefix}ld}"
libtool="${LIBTOOL-${cross_prefix}libtool}"
strip="${STRIP-${cross_prefix}strip}"
windres="${WINDRES-${cross_prefix}windres}"
-pkg_config="${PKG_CONFIG-${cross_prefix}pkg-config}"
+pkg_config_exe="${PKG_CONFIG-${cross_prefix}pkg-config}"
+query_pkg_config() {
+ "${pkg_config_exe}" ${QEMU_PKG_CONFIG_FLAGS} "$@"
+}
+pkg_config=query_pkg_config
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
# default flags for all hosts
@@ -553,6 +558,7 @@ for opt do
--static)
static="yes"
LDFLAGS="-static $LDFLAGS"
+ QEMU_PKG_CONFIG_FLAGS="--static $QEMU_PKG_CONFIG_FLAGS"
;;
--mandir=*) mandir="$optarg"
;;
@@ -667,6 +673,10 @@ for opt do
;;
--enable-tcg-interpreter) tcg_interpreter="yes"
;;
+ --disable-cap-ng) cap_ng="no"
+ ;;
+ --enable-cap-ng) cap_ng="yes"
+ ;;
--disable-spice) spice="no"
;;
--enable-spice) spice="yes"
@@ -766,6 +776,10 @@ for opt do
;;
--enable-rbd) rbd="yes"
;;
+ --disable-xfsctl) xfs="no"
+ ;;
+ --enable-xfsctl) xfs="yes"
+ ;;
--disable-smartcard) smartcard="no"
;;
--enable-smartcard) smartcard="yes"
@@ -1044,6 +1058,8 @@ echo " --disable-vde disable support for vde network"
echo " --enable-vde enable support for vde network"
echo " --disable-linux-aio disable Linux AIO support"
echo " --enable-linux-aio enable Linux AIO support"
+echo " --disable-cap-ng disable libcap-ng support"
+echo " --enable-cap-ng enable libcap-ng support"
echo " --disable-attr disables attr and xattr support"
echo " --enable-attr enable attr and xattr support"
echo " --disable-blobs disable installing provided firmware blobs"
@@ -1445,8 +1461,8 @@ fi
##########################################
# pkg-config probe
-if ! has $pkg_config; then
- echo "Error: pkg-config binary '$pkg_config' not found"
+if ! has "$pkg_config_exe"; then
+ echo "Error: pkg-config binary '$pkg_config_exe' not found"
exit 1
fi
@@ -1736,6 +1752,29 @@ EOF
fi
##########################################
+# libcap-ng library probe
+if test "$cap_ng" != "no" ; then
+ cap_libs="-lcap-ng"
+ cat > $TMPC << EOF
+#include <cap-ng.h>
+int main(void)
+{
+ capng_capability_to_name(CAPNG_EFFECTIVE);
+ return 0;
+}
+EOF
+ if compile_prog "" "$cap_libs" ; then
+ cap_ng=yes
+ libs_tools="$cap_libs $libs_tools"
+ else
+ if test "$cap_ng" = "yes" ; then
+ feature_not_found "cap_ng"
+ fi
+ cap_ng=no
+ fi
+fi
+
+##########################################
# Sound support libraries probe
audio_drv_probe()
@@ -2519,11 +2558,16 @@ if test "$smartcard" != "no" ; then
smartcard_cflags=""
# TODO - what's the minimal nss version we support?
if test "$smartcard_nss" != "no"; then
- if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 ; then
+ cat > $TMPC << EOF
+#include <pk11pub.h>
+int main(void) { PK11_FreeSlot(0); return 0; }
+EOF
+ smartcard_cflags="-I\$(SRC_PATH)/libcacard"
+ libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
+ libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
+ if $pkg_config --atleast-version=3.12.8 nss >/dev/null 2>&1 && \
+ compile_prog "$smartcard_cflags $libcacard_cflags" "$libcacard_libs"; then
smartcard_nss="yes"
- smartcard_cflags="-I\$(SRC_PATH)/libcacard"
- libcacard_libs=$($pkg_config --libs nss 2>/dev/null)
- libcacard_cflags=$($pkg_config --cflags nss 2>/dev/null)
QEMU_CFLAGS="$QEMU_CFLAGS $smartcard_cflags $libcacard_cflags"
LIBS="$libcacard_libs $LIBS"
else
@@ -2862,6 +2906,7 @@ echo "fdatasync $fdatasync"
echo "madvise $madvise"
echo "posix_madvise $posix_madvise"
echo "uuid support $uuid"
+echo "libcap-ng support $cap_ng"
echo "vhost-net support $vhost_net"
echo "Trace backend $trace_backend"
echo "Trace output file $trace_file-<pid>"
@@ -2896,6 +2941,9 @@ echo "datadir=$datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
echo "docdir=$docdir" >> $config_host_mak
echo "confdir=$confdir" >> $config_host_mak
+echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
+echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
+echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
if test "$debug_tcg" = "yes" ; then
@@ -2965,6 +3013,9 @@ fi
if test "$vde" = "yes" ; then
echo "CONFIG_VDE=y" >> $config_host_mak
fi
+if test "$cap_ng" = "yes" ; then
+ echo "CONFIG_LIBCAP=y" >> $config_host_mak
+fi
for card in $audio_card_list; do
def=CONFIG_`echo $card | tr '[:lower:]' '[:upper:]'`
echo "$def=y" >> $config_host_mak
@@ -3363,6 +3414,7 @@ mkdir -p $target_dir/fpu
mkdir -p $target_dir/tcg
mkdir -p $target_dir/ide
mkdir -p $target_dir/9pfs
+mkdir -p $target_dir/kvm
if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
mkdir -p $target_dir/nwfpe
fi
@@ -3780,7 +3832,7 @@ DIRS="$DIRS pc-bios/spapr-rtas"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS fsdev ui"
DIRS="$DIRS qapi qapi-generated"
-DIRS="$DIRS qga trace"
+DIRS="$DIRS qga trace qom"
FILES="Makefile tests/tcg/Makefile qdict-test-data.txt"
FILES="$FILES tests/tcg/cris/Makefile tests/tcg/cris/.gdbinit"
FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps"
diff --git a/console.h b/console.h
index 9466886b59..6ba0d5ddf3 100644
--- a/console.h
+++ b/console.h
@@ -4,7 +4,6 @@
#include "qemu-char.h"
#include "qdict.h"
#include "notify.h"
-#include "qerror.h"
#include "monitor.h"
/* keyboard/mouse support */
@@ -384,12 +383,10 @@ int vnc_display_pw_expire(DisplayState *ds, time_t expires);
#else
static inline int vnc_display_password(DisplayState *ds, const char *password)
{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
}
static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
return -ENODEV;
};
#endif
diff --git a/cpus.c b/cpus.c
index 2dae549225..f45a438b29 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1217,7 +1217,11 @@ void qmp_inject_nmi(Error **errp)
CPUState *env;
for (env = first_cpu; env != NULL; env = env->next_cpu) {
- cpu_interrupt(env, CPU_INTERRUPT_NMI);
+ if (!env->apic_state) {
+ cpu_interrupt(env, CPU_INTERRUPT_NMI);
+ } else {
+ apic_deliver_nmi(env->apic_state);
+ }
}
#else
error_set(errp, QERR_UNSUPPORTED);
diff --git a/default-configs/alpha-softmmu.mak b/default-configs/alpha-softmmu.mak
index bd1dd95a2a..501dd413b7 100644
--- a/default-configs/alpha-softmmu.mak
+++ b/default-configs/alpha-softmmu.mak
@@ -4,7 +4,9 @@ include pci.mak
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
+CONFIG_VGA_CIRRUS=y
CONFIG_IDE_CORE=y
CONFIG_IDE_QDEV=y
CONFIG_VMWARE_VGA=y
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 8d1174f177..e542b4f8ee 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -2,6 +2,7 @@
include pci.mak
CONFIG_GDBSTUB_XML=y
+CONFIG_VGA=y
CONFIG_ISA_MMIO=y
CONFIG_NAND=y
CONFIG_ECC=y
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index e67ebb360e..662348ef11 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -1,8 +1,10 @@
# Default configuration for i386-softmmu
include pci.mak
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_VMMOUSE=y
CONFIG_SERIAL=y
diff --git a/default-configs/mips-softmmu.mak b/default-configs/mips-softmmu.mak
index 94a34862dc..308d04aeab 100644
--- a/default-configs/mips-softmmu.mak
+++ b/default-configs/mips-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mips64-linux-user.mak b/default-configs/mips64-linux-user.mak
new file mode 100644
index 0000000000..1598bfcf7d
--- /dev/null
+++ b/default-configs/mips64-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64-linux-user
diff --git a/default-configs/mips64-softmmu.mak b/default-configs/mips64-softmmu.mak
index b5d310816f..f1b92da8a3 100644
--- a/default-configs/mips64-softmmu.mak
+++ b/default-configs/mips64-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mips64el-linux-user.mak b/default-configs/mips64el-linux-user.mak
new file mode 100644
index 0000000000..629f084086
--- /dev/null
+++ b/default-configs/mips64el-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mips64el-linux-user
diff --git a/default-configs/mips64el-softmmu.mak b/default-configs/mips64el-softmmu.mak
index 2831f44f2a..567396c84f 100644
--- a/default-configs/mips64el-softmmu.mak
+++ b/default-configs/mips64el-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mipsel-softmmu.mak b/default-configs/mipsel-softmmu.mak
index 14c949df13..a8e421b151 100644
--- a/default-configs/mipsel-softmmu.mak
+++ b/default-configs/mipsel-softmmu.mak
@@ -3,9 +3,11 @@
include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_ESP=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
CONFIG_VGA_ISA_MM=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
diff --git a/default-configs/mipsn32-linux-user.mak b/default-configs/mipsn32-linux-user.mak
new file mode 100644
index 0000000000..5b97919794
--- /dev/null
+++ b/default-configs/mipsn32-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsn32-linux-user
diff --git a/default-configs/mipsn32el-linux-user.mak b/default-configs/mipsn32el-linux-user.mak
new file mode 100644
index 0000000000..d6367ff987
--- /dev/null
+++ b/default-configs/mipsn32el-linux-user.mak
@@ -0,0 +1 @@
+# Default configuration for mipsn32el-linux-user
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 22bd3502d4..9d3e1dbda1 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -4,6 +4,7 @@ CONFIG_VIRTIO=y
CONFIG_USB_UHCI=y
CONFIG_USB_OHCI=y
CONFIG_USB_EHCI=y
+CONFIG_USB_XHCI=y
CONFIG_NE2000_PCI=y
CONFIG_EEPRO100_PCI=y
CONFIG_PCNET_PCI=y
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index c85cdceb15..1a768fc519 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -5,15 +5,19 @@ CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_I8254=y
CONFIG_PCKBD=y
CONFIG_FDC=y
CONFIG_DMA=y
+CONFIG_I82374=y
CONFIG_OPENPIC=y
CONFIG_PREP_PCI=y
+CONFIG_I82378=y
CONFIG_MACIO=y
+CONFIG_PCSPK=y
CONFIG_CUDA=y
CONFIG_ADB=y
CONFIG_MAC_NVRAM=y
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak
index 8874115d81..f490368c64 100644
--- a/default-configs/ppc64-softmmu.mak
+++ b/default-configs/ppc64-softmmu.mak
@@ -5,6 +5,7 @@ CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_I8254=y
diff --git a/default-configs/ppcemb-softmmu.mak b/default-configs/ppcemb-softmmu.mak
index 5db7205267..829f462105 100644
--- a/default-configs/ppcemb-softmmu.mak
+++ b/default-configs/ppcemb-softmmu.mak
@@ -5,6 +5,7 @@ CONFIG_GDBSTUB_XML=y
CONFIG_ISA_MMIO=y
CONFIG_ESCC=y
CONFIG_M48T59=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_SERIAL=y
CONFIG_I8254=y
diff --git a/default-configs/sparc64-softmmu.mak b/default-configs/sparc64-softmmu.mak
index d8f17e7b46..c9a36c1e46 100644
--- a/default-configs/sparc64-softmmu.mak
+++ b/default-configs/sparc64-softmmu.mak
@@ -4,7 +4,9 @@ include pci.mak
CONFIG_ISA_MMIO=y
CONFIG_M48T59=y
CONFIG_PTIMER=y
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
+CONFIG_VGA_CIRRUS=y
CONFIG_SERIAL=y
CONFIG_PARALLEL=y
CONFIG_PCKBD=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index b75757ee5f..b445be2059 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -1,8 +1,10 @@
# Default configuration for x86_64-softmmu
include pci.mak
+CONFIG_VGA=y
CONFIG_VGA_PCI=y
CONFIG_VGA_ISA=y
+CONFIG_VGA_CIRRUS=y
CONFIG_VMWARE_VGA=y
CONFIG_VMMOUSE=y
CONFIG_SERIAL=y
diff --git a/docs/live-block-ops.txt b/docs/live-block-ops.txt
new file mode 100644
index 0000000000..a257087401
--- /dev/null
+++ b/docs/live-block-ops.txt
@@ -0,0 +1,58 @@
+LIVE BLOCK OPERATIONS
+=====================
+
+High level description of live block operations. Note these are not
+supported for use with the raw format at the moment.
+
+Snapshot live merge
+===================
+
+Given a snapshot chain, described in this document in the following
+format:
+
+[A] -> [B] -> [C] -> [D]
+
+Where the rightmost object ([D] in the example) described is the current
+image which the guest OS has write access to. To the left of it is its base
+image, and so on accordingly until the leftmost image, which has no
+base.
+
+The snapshot live merge operation transforms such a chain into a
+smaller one with fewer elements, such as this transformation relative
+to the first example:
+
+[A] -> [D]
+
+Currently only forward merge with target being the active image is
+supported, that is, data copy is performed in the right direction with
+destination being the rightmost image.
+
+The operation is implemented in QEMU through image streaming facilities.
+
+The basic idea is to execute 'block_stream virtio0' while the guest is
+running. Progress can be monitored using 'info block-jobs'. When the
+streaming operation completes it raises a QMP event. 'block_stream'
+copies data from the backing file(s) into the active image. When finished,
+it adjusts the backing file pointer.
+
+The 'base' parameter specifies an image which data need not be streamed from.
+This image will be used as the backing file for the active image when the
+operation is finished.
+
+In the example above, the command would be:
+
+(qemu) block_stream virtio0 A
+
+
+Live block copy
+===============
+
+To copy an in use image to another destination in the filesystem, one
+should create a live snapshot in the desired destination, then stream
+into that image. Example:
+
+(qemu) snapshot_blkdev ide0-hd0 /new-path/disk.img qcow2
+
+(qemu) block_stream ide0-hd0
+
+
diff --git a/exec-obsolete.h b/exec-obsolete.h
index c412be95e0..94c23d0951 100644
--- a/exec-obsolete.h
+++ b/exec-obsolete.h
@@ -59,10 +59,21 @@ static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr)
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS];
}
-static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
+static inline int cpu_physical_memory_get_dirty(ram_addr_t start,
+ ram_addr_t length,
int dirty_flags)
{
- return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
+ int ret = 0;
+ uint8_t *p;
+ ram_addr_t addr, end;
+
+ end = TARGET_PAGE_ALIGN(start + length);
+ start &= TARGET_PAGE_MASK;
+ p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+ for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+ ret |= *p++ & dirty_flags;
+ }
+ return ret;
}
static inline void cpu_physical_memory_set_dirty(ram_addr_t addr)
@@ -76,18 +87,35 @@ static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr,
return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags;
}
+static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
+ ram_addr_t length,
+ int dirty_flags)
+{
+ uint8_t *p;
+ ram_addr_t addr, end;
+
+ end = TARGET_PAGE_ALIGN(start + length);
+ start &= TARGET_PAGE_MASK;
+ p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
+ for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+ *p++ |= dirty_flags;
+ }
+}
+
static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start,
- int length,
+ ram_addr_t length,
int dirty_flags)
{
- int i, mask, len;
+ int mask;
uint8_t *p;
+ ram_addr_t addr, end;
- len = length >> TARGET_PAGE_BITS;
+ end = TARGET_PAGE_ALIGN(start + length);
+ start &= TARGET_PAGE_MASK;
mask = ~dirty_flags;
p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS);
- for (i = 0; i < len; i++) {
- p[i] &= mask;
+ for (addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
+ *p++ &= mask;
}
}
diff --git a/exec.c b/exec.c
index 7f9f730250..b81677ade9 100644
--- a/exec.c
+++ b/exec.c
@@ -1876,8 +1876,18 @@ static CPUTLBEntry s_cputlb_empty_entry = {
.addend = -1,
};
-/* NOTE: if flush_global is true, also flush global entries (not
- implemented yet) */
+/* NOTE:
+ * If flush_global is true (the usual case), flush all tlb entries.
+ * If flush_global is false, flush (at least) all tlb entries not
+ * marked global.
+ *
+ * Since QEMU doesn't currently implement a global/not-global flag
+ * for tlb entries, at the moment tlb_flush() will also flush all
+ * tlb entries in the flush_global == false case. This is OK because
+ * CPU architectures generally permit an implementation to drop
+ * entries from the TLB at any time, so flushing more entries than
+ * required is only an efficiency issue, not a correctness issue.
+ */
void tlb_flush(CPUState *env, int flush_global)
{
int i;
@@ -4390,6 +4400,20 @@ tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong addr)
return qemu_ram_addr_from_host_nofail(p);
}
+/*
+ * A helper function for the _utterly broken_ virtio device model to find out if
+ * it's running on a big endian machine. Don't do this at home kids!
+ */
+bool virtio_is_big_endian(void);
+bool virtio_is_big_endian(void)
+{
+#if defined(TARGET_WORDS_BIGENDIAN)
+ return true;
+#else
+ return false;
+#endif
+}
+
#define MMUSUFFIX _cmmu
#undef GETPC
#define GETPC() NULL
diff --git a/hmp-commands.hx b/hmp-commands.hx
index a586498495..573b823347 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -69,14 +69,54 @@ but should be used with extreme caution. Note that this command only
resizes image files, it can not resize block devices like LVM volumes.
ETEXI
+ {
+ .name = "block_stream",
+ .args_type = "device:B,base:s?",
+ .params = "device [base]",
+ .help = "copy data from a backing file into a block device",
+ .mhandler.cmd = hmp_block_stream,
+ },
+
+STEXI
+@item block_stream
+@findex block_stream
+Copy data from a backing file into a block device.
+ETEXI
+
+ {
+ .name = "block_job_set_speed",
+ .args_type = "device:B,value:o",
+ .params = "device value",
+ .help = "set maximum speed for a background block operation",
+ .mhandler.cmd = hmp_block_job_set_speed,
+ },
+
+STEXI
+@item block_job_set_stream
+@findex block_job_set_stream
+Set maximum speed for a background block operation.
+ETEXI
+
+ {
+ .name = "block_job_cancel",
+ .args_type = "device:B",
+ .params = "device",
+ .help = "stop an active block streaming operation",
+ .mhandler.cmd = hmp_block_job_cancel,
+ },
+
+STEXI
+@item block_job_cancel
+@findex block_job_cancel
+Stop an active block streaming operation.
+ETEXI
{
.name = "eject",
.args_type = "force:-f,device:B",
.params = "[-f] device",
.help = "eject a removable medium (use -f to force it)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_eject,
+ .mhandler.cmd = hmp_eject,
},
STEXI
@@ -108,8 +148,7 @@ ETEXI
.args_type = "device:B,target:F,arg:s?",
.params = "device filename [format]",
.help = "change a removable medium, optional format",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_change,
+ .mhandler.cmd = hmp_change,
},
STEXI
@@ -1204,8 +1243,7 @@ ETEXI
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
.params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
.help = "change I/O throttle limits for a block drive",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_io_throttle,
+ .mhandler.cmd = hmp_block_set_io_throttle,
},
STEXI
@@ -1219,8 +1257,7 @@ ETEXI
.args_type = "protocol:s,password:s,connected:s?",
.params = "protocol password action-if-connected",
.help = "set spice/vnc password",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = set_password,
+ .mhandler.cmd = hmp_set_password,
},
STEXI
@@ -1240,8 +1277,7 @@ ETEXI
.args_type = "protocol:s,time:s",
.params = "protocol time",
.help = "set spice/vnc password expire-time",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = expire_password,
+ .mhandler.cmd = hmp_expire_password,
},
STEXI
diff --git a/hmp.c b/hmp.c
index 8a777804de..8ff8c9434e 100644
--- a/hmp.c
+++ b/hmp.c
@@ -509,6 +509,42 @@ void hmp_info_pci(Monitor *mon)
qapi_free_PciInfoList(info_list);
}
+void hmp_info_block_jobs(Monitor *mon)
+{
+ BlockJobInfoList *list;
+ Error *err = NULL;
+
+ list = qmp_query_block_jobs(&err);
+ assert(!err);
+
+ if (!list) {
+ monitor_printf(mon, "No active jobs\n");
+ return;
+ }
+
+ while (list) {
+ if (strcmp(list->value->type, "stream") == 0) {
+ monitor_printf(mon, "Streaming device %s: Completed %" PRId64
+ " of %" PRId64 " bytes, speed limit %" PRId64
+ " bytes/s\n",
+ list->value->device,
+ list->value->offset,
+ list->value->len,
+ list->value->speed);
+ } else {
+ monitor_printf(mon, "Type %s, device %s: Completed %" PRId64
+ " of %" PRId64 " bytes, speed limit %" PRId64
+ " bytes/s\n",
+ list->value->type,
+ list->value->device,
+ list->value->offset,
+ list->value->len,
+ list->value->speed);
+ }
+ list = list->next;
+ }
+}
+
void hmp_quit(Monitor *mon, const QDict *qdict)
{
monitor_suspend(mon);
@@ -681,3 +717,137 @@ void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
int64_t value = qdict_get_int(qdict, "value");
qmp_migrate_set_speed(value, NULL);
}
+
+void hmp_set_password(Monitor *mon, const QDict *qdict)
+{
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *password = qdict_get_str(qdict, "password");
+ const char *connected = qdict_get_try_str(qdict, "connected");
+ Error *err = NULL;
+
+ qmp_set_password(protocol, password, !!connected, connected, &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_expire_password(Monitor *mon, const QDict *qdict)
+{
+ const char *protocol = qdict_get_str(qdict, "protocol");
+ const char *whenstr = qdict_get_str(qdict, "time");
+ Error *err = NULL;
+
+ qmp_expire_password(protocol, whenstr, &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_eject(Monitor *mon, const QDict *qdict)
+{
+ int force = qdict_get_try_bool(qdict, "force", 0);
+ const char *device = qdict_get_str(qdict, "device");
+ Error *err = NULL;
+
+ qmp_eject(device, true, force, &err);
+ hmp_handle_error(mon, &err);
+}
+
+static void hmp_change_read_arg(Monitor *mon, const char *password,
+ void *opaque)
+{
+ qmp_change_vnc_password(password, NULL);
+ monitor_read_command(mon, 1);
+}
+
+static void cb_hmp_change_bdrv_pwd(Monitor *mon, const char *password,
+ void *opaque)
+{
+ Error *encryption_err = opaque;
+ Error *err = NULL;
+ const char *device;
+
+ device = error_get_field(encryption_err, "device");
+
+ qmp_block_passwd(device, password, &err);
+ hmp_handle_error(mon, &err);
+ error_free(encryption_err);
+
+ monitor_read_command(mon, 1);
+}
+
+void hmp_change(Monitor *mon, const QDict *qdict)
+{
+ const char *device = qdict_get_str(qdict, "device");
+ const char *target = qdict_get_str(qdict, "target");
+ const char *arg = qdict_get_try_str(qdict, "arg");
+ Error *err = NULL;
+
+ if (strcmp(device, "vnc") == 0 &&
+ (strcmp(target, "passwd") == 0 ||
+ strcmp(target, "password") == 0)) {
+ if (!arg) {
+ monitor_read_password(mon, hmp_change_read_arg, NULL);
+ return;
+ }
+ }
+
+ qmp_change(device, target, !!arg, arg, &err);
+ if (error_is_type(err, QERR_DEVICE_ENCRYPTED)) {
+ monitor_printf(mon, "%s (%s) is encrypted.\n",
+ error_get_field(err, "device"),
+ error_get_field(err, "filename"));
+ if (!monitor_get_rs(mon)) {
+ monitor_printf(mon,
+ "terminal does not support password prompting\n");
+ error_free(err);
+ return;
+ }
+ readline_start(monitor_get_rs(mon), "Password: ", 1,
+ cb_hmp_change_bdrv_pwd, err);
+ return;
+ }
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict)
+{
+ Error *err = NULL;
+
+ qmp_block_set_io_throttle(qdict_get_str(qdict, "device"),
+ qdict_get_int(qdict, "bps"),
+ qdict_get_int(qdict, "bps_rd"),
+ qdict_get_int(qdict, "bps_wr"),
+ qdict_get_int(qdict, "iops"),
+ qdict_get_int(qdict, "iops_rd"),
+ qdict_get_int(qdict, "iops_wr"), &err);
+ hmp_handle_error(mon, &err);
+}
+
+void hmp_block_stream(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+ const char *device = qdict_get_str(qdict, "device");
+ const char *base = qdict_get_try_str(qdict, "base");
+
+ qmp_block_stream(device, base != NULL, base, &error);
+
+ hmp_handle_error(mon, &error);
+}
+
+void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+ const char *device = qdict_get_str(qdict, "device");
+ int64_t value = qdict_get_int(qdict, "value");
+
+ qmp_block_job_set_speed(device, value, &error);
+
+ hmp_handle_error(mon, &error);
+}
+
+void hmp_block_job_cancel(Monitor *mon, const QDict *qdict)
+{
+ Error *error = NULL;
+ const char *device = qdict_get_str(qdict, "device");
+
+ qmp_block_job_cancel(device, &error);
+
+ hmp_handle_error(mon, &error);
+}
diff --git a/hmp.h b/hmp.h
index 093242d626..18eecbdcb9 100644
--- a/hmp.h
+++ b/hmp.h
@@ -32,6 +32,7 @@ void hmp_info_vnc(Monitor *mon);
void hmp_info_spice(Monitor *mon);
void hmp_info_balloon(Monitor *mon);
void hmp_info_pci(Monitor *mon);
+void hmp_info_block_jobs(Monitor *mon);
void hmp_quit(Monitor *mon, const QDict *qdict);
void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
@@ -49,5 +50,13 @@ void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_set_password(Monitor *mon, const QDict *qdict);
+void hmp_expire_password(Monitor *mon, const QDict *qdict);
+void hmp_eject(Monitor *mon, const QDict *qdict);
+void hmp_change(Monitor *mon, const QDict *qdict);
+void hmp_block_set_io_throttle(Monitor *mon, const QDict *qdict);
+void hmp_block_stream(Monitor *mon, const QDict *qdict);
+void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict);
+void hmp_block_job_cancel(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c
index 41a1a820e0..791a5572bb 100644
--- a/hw/9pfs/virtio-9p-device.c
+++ b/hw/9pfs/virtio-9p-device.c
@@ -154,29 +154,39 @@ static int virtio_9p_init_pci(PCIDevice *pci_dev)
return 0;
}
-static PCIDeviceInfo virtio_9p_info = {
- .qdev.name = "virtio-9p-pci",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_9p_init_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = 0x1009,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = 0x2,
- .qdev.props = (Property[]) {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
- DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
+static Property virtio_9p_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag),
+ DEFINE_PROP_STRING("fsdev", VirtIOPCIProxy, fsconf.fsdev_id),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_9p_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_9p_init_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = 0x1009;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = 0x2;
+ dc->props = virtio_9p_properties;
+ dc->reset = virtio_pci_reset;
+}
+
+static TypeInfo virtio_9p_info = {
+ .name = "virtio-9p-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_9p_class_init,
};
static void virtio_9p_register_devices(void)
{
- pci_qdev_register(&virtio_9p_info);
+ type_register_static(&virtio_9p_info);
virtio_9p_set_fd_limit();
}
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 3ef0e138c4..19de12b4b4 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -11,9 +11,8 @@
#include "sysbus.h"
/* Configuration for arm_gic.c:
- * number of external IRQ lines, max number of CPUs, how to ID current CPU
+ * max number of CPUs, how to ID current CPU
*/
-#define GIC_NIRQ 96
#define NCPU 4
static inline int
@@ -37,6 +36,7 @@ typedef struct a9mp_priv_state {
MemoryRegion ptimer_iomem;
MemoryRegion container;
DeviceState *mptimer;
+ uint32_t num_irq;
} a9mp_priv_state;
static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
@@ -153,7 +153,7 @@ static int a9mp_priv_init(SysBusDevice *dev)
hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
}
- gic_init(&s->gic, s->num_cpu);
+ gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
@@ -208,21 +208,39 @@ static const VMStateDescription vmstate_a9mp_priv = {
}
};
-static SysBusDeviceInfo a9mp_priv_info = {
- .init = a9mp_priv_init,
- .qdev.name = "a9mpcore_priv",
- .qdev.size = sizeof(a9mp_priv_state),
- .qdev.vmsd = &vmstate_a9mp_priv,
- .qdev.reset = a9mp_priv_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property a9mp_priv_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
+ /* The Cortex-A9MP may have anything from 0 to 224 external interrupt
+ * IRQ lines (with another 32 internal). We default to 64+32, which
+ * is the number provided by the Cortex-A9MP test chip in the
+ * Realview PBX-A9 and Versatile Express A9 development boards.
+ * Other boards may differ and should set this property appropriately.
+ */
+ DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 96),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void a9mp_priv_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = a9mp_priv_init;
+ dc->props = a9mp_priv_properties;
+ dc->vmsd = &vmstate_a9mp_priv;
+ dc->reset = a9mp_priv_reset;
+}
+
+static TypeInfo a9mp_priv_info = {
+ .name = "a9mpcore_priv",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(a9mp_priv_state),
+ .class_init = a9mp_priv_class_init,
};
static void a9mp_register_devices(void)
{
- sysbus_register_withprop(&a9mp_priv_info);
+ type_register_static(&a9mp_priv_info);
}
device_init(a9mp_register_devices)
diff --git a/hw/ac97.c b/hw/ac97.c
index 03be99b08a..7bf9171487 100644
--- a/hw/ac97.c
+++ b/hw/ac97.c
@@ -1175,17 +1175,17 @@ static const VMStateDescription vmstate_ac97_bm_regs = {
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField []) {
- VMSTATE_UINT32(bdbar, AC97BusMasterRegs),
- VMSTATE_UINT8(civ, AC97BusMasterRegs),
- VMSTATE_UINT8(lvi, AC97BusMasterRegs),
- VMSTATE_UINT16(sr, AC97BusMasterRegs),
- VMSTATE_UINT16(picb, AC97BusMasterRegs),
- VMSTATE_UINT8(piv, AC97BusMasterRegs),
- VMSTATE_UINT8(cr, AC97BusMasterRegs),
- VMSTATE_UINT32(bd_valid, AC97BusMasterRegs),
- VMSTATE_UINT32(bd.addr, AC97BusMasterRegs),
- VMSTATE_UINT32(bd.ctl_len, AC97BusMasterRegs),
- VMSTATE_END_OF_LIST()
+ VMSTATE_UINT32 (bdbar, AC97BusMasterRegs),
+ VMSTATE_UINT8 (civ, AC97BusMasterRegs),
+ VMSTATE_UINT8 (lvi, AC97BusMasterRegs),
+ VMSTATE_UINT16 (sr, AC97BusMasterRegs),
+ VMSTATE_UINT16 (picb, AC97BusMasterRegs),
+ VMSTATE_UINT8 (piv, AC97BusMasterRegs),
+ VMSTATE_UINT8 (cr, AC97BusMasterRegs),
+ VMSTATE_UINT32 (bd_valid, AC97BusMasterRegs),
+ VMSTATE_UINT32 (bd.addr, AC97BusMasterRegs),
+ VMSTATE_UINT32 (bd.ctl_len, AC97BusMasterRegs),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1224,15 +1224,15 @@ static const VMStateDescription vmstate_ac97 = {
.minimum_version_id_old = 2,
.post_load = ac97_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, AC97LinkState),
- VMSTATE_UINT32(glob_cnt, AC97LinkState),
- VMSTATE_UINT32(glob_sta, AC97LinkState),
- VMSTATE_UINT32(cas, AC97LinkState),
- VMSTATE_STRUCT_ARRAY(bm_regs, AC97LinkState, 3, 1,
- vmstate_ac97_bm_regs, AC97BusMasterRegs),
- VMSTATE_BUFFER(mixer_data, AC97LinkState),
- VMSTATE_UNUSED_TEST(is_version_2, 3),
- VMSTATE_END_OF_LIST()
+ VMSTATE_PCI_DEVICE (dev, AC97LinkState),
+ VMSTATE_UINT32 (glob_cnt, AC97LinkState),
+ VMSTATE_UINT32 (glob_sta, AC97LinkState),
+ VMSTATE_UINT32 (cas, AC97LinkState),
+ VMSTATE_STRUCT_ARRAY (bm_regs, AC97LinkState, 3, 1,
+ vmstate_ac97_bm_regs, AC97BusMasterRegs),
+ VMSTATE_BUFFER (mixer_data, AC97LinkState),
+ VMSTATE_UNUSED_TEST (is_version_2, 3),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1243,7 +1243,7 @@ static const MemoryRegionPortio nam_portio[] = {
{ 0, 256 * 1, 1, .write = nam_writeb, },
{ 0, 256 * 2, 2, .write = nam_writew, },
{ 0, 256 * 4, 4, .write = nam_writel, },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
static const MemoryRegionOps ac97_io_nam_ops = {
@@ -1257,7 +1257,7 @@ static const MemoryRegionPortio nabm_portio[] = {
{ 0, 64 * 1, 1, .write = nabm_writeb, },
{ 0, 64 * 2, 2, .write = nabm_writew, },
{ 0, 64 * 4, 4, .write = nabm_writel, },
- PORTIO_END_OF_LIST()
+ PORTIO_END_OF_LIST ()
};
static const MemoryRegionOps ac97_io_nabm_ops = {
@@ -1344,26 +1344,37 @@ int ac97_init (PCIBus *bus)
return 0;
}
-static PCIDeviceInfo ac97_info = {
- .qdev.name = "AC97",
- .qdev.desc = "Intel 82801AA AC97 Audio",
- .qdev.size = sizeof (AC97LinkState),
- .qdev.vmsd = &vmstate_ac97,
- .init = ac97_initfn,
- .exit = ac97_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801AA_5,
- .revision = 0x01,
- .class_id = PCI_CLASS_MULTIMEDIA_AUDIO,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("use_broken_id", AC97LinkState, use_broken_id, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ac97_properties[] = {
+ DEFINE_PROP_UINT32 ("use_broken_id", AC97LinkState, use_broken_id, 0),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void ac97_class_init (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+ k->init = ac97_initfn;
+ k->exit = ac97_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801AA_5;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+ dc->desc = "Intel 82801AA AC97 Audio";
+ dc->vmsd = &vmstate_ac97;
+ dc->props = ac97_properties;
+}
+
+static TypeInfo ac97_info = {
+ .name = "AC97",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof (AC97LinkState),
+ .class_init = ac97_class_init,
};
static void ac97_register (void)
{
- pci_qdev_register (&ac97_info);
+ type_register_static (&ac97_info);
}
device_init (ac97_register);
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index bdc55a1eaa..21484aec42 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -280,11 +280,11 @@ static void piix4_update_hotplug(PIIX4PMState *s)
s->pci0_hotplug_enable = ~0;
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
- PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
- PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *pdev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pdev);
int slot = PCI_SLOT(pdev->devfn);
- if (info->no_hotplug) {
+ if (pc->no_hotplug) {
s->pci0_hotplug_enable &= ~(1 << slot);
}
}
@@ -396,28 +396,39 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
return s->smb.smbus;
}
-static PCIDeviceInfo piix4_pm_info = {
- .qdev.name = "PIIX4_PM",
- .qdev.desc = "PM",
- .qdev.size = sizeof(PIIX4PMState),
- .qdev.vmsd = &vmstate_acpi,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix4_pm_initfn,
- .config_write = pm_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_3,
- .revision = 0x03,
- .class_id = PCI_CLASS_BRIDGE_OTHER,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property piix4_pm_properties[] = {
+ DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void piix4_pm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = piix4_pm_initfn;
+ k->config_write = pm_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB_3;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+ dc->desc = "PM";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_acpi;
+ dc->props = piix4_pm_properties;
+}
+
+static TypeInfo piix4_pm_info = {
+ .name = "PIIX4_PM",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX4PMState),
+ .class_init = piix4_pm_class_init,
};
static void piix4_pm_register(void)
{
- pci_qdev_register(&piix4_pm_info);
+ type_register_static(&piix4_pm_info);
}
device_init(piix4_pm_register);
@@ -485,14 +496,12 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
{
BusState *bus = opaque;
DeviceState *qdev, *next;
- PCIDevice *dev;
- PCIDeviceInfo *info;
int slot = ffs(val) - 1;
QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
- dev = DO_UPCAST(PCIDevice, qdev, qdev);
- info = container_of(qdev->info, PCIDeviceInfo, qdev);
- if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
+ PCIDevice *dev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ if (PCI_SLOT(dev->devfn) == slot && !pc->no_hotplug) {
qdev_free(qdev);
}
}
@@ -553,7 +562,7 @@ static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
{
int slot = PCI_SLOT(dev->devfn);
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
- DO_UPCAST(PCIDevice, qdev, qdev));
+ PCI_DEVICE(qdev));
/* Don't send event when device is enabled during qemu machine creation:
* it is present on boot, no hotplug event is necessary. We do send an
diff --git a/hw/adlib.c b/hw/adlib.c
index dd8b1888cf..d39cd97384 100644
--- a/hw/adlib.c
+++ b/hw/adlib.c
@@ -164,7 +164,7 @@ static void timer_handler (int c, double interval_Sec)
s->ticking[n] = 1;
#ifdef DEBUG
- interval = get_ticks_per_sec() * interval_Sec;
+ interval = get_ticks_per_sec () * interval_Sec;
exp = qemu_get_clock_ns (vm_clock) + interval;
s->exp[n] = exp;
#endif
diff --git a/hw/ads7846.c b/hw/ads7846.c
index de3f7af127..3cfdecbe5c 100644
--- a/hw/ads7846.c
+++ b/hw/ads7846.c
@@ -153,16 +153,24 @@ static int ads7846_init(SSISlave *dev)
return 0;
}
-static SSISlaveInfo ads7846_info = {
- .qdev.name ="ads7846",
- .qdev.size = sizeof(ADS7846State),
- .init = ads7846_init,
- .transfer = ads7846_transfer
+static void ads7846_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = ads7846_init;
+ k->transfer = ads7846_transfer;
+}
+
+static TypeInfo ads7846_info = {
+ .name = "ads7846",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ADS7846State),
+ .class_init = ads7846_class_init,
};
static void ads7846_register_devices(void)
{
- ssi_register_slave(&ads7846_info);
+ type_register_static(&ads7846_info);
}
device_init(ads7846_register_devices)
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c
index e9757028af..673557781e 100644
--- a/hw/alpha_pci.c
+++ b/hw/alpha_pci.c
@@ -121,10 +121,8 @@ void alpha_pci_vga_setup(PCIBus *pci_bus)
pci_cirrus_vga_init(pci_bus);
return;
case VGA_VMWARE:
- if (pci_vmsvga_init(pci_bus)) {
- return;
- }
- break;
+ pci_vmsvga_init(pci_bus);
+ return;
}
/* If VGA is enabled at all, and one of the above didn't work, then
fallback to Standard VGA. */
diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c
index 7d924a3f08..736c28a3a9 100644
--- a/hw/alpha_typhoon.c
+++ b/hw/alpha_typhoon.c
@@ -808,15 +808,24 @@ static int typhoon_pcihost_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo typhoon_pcihost_info = {
- .init = typhoon_pcihost_init,
- .qdev.name = "typhoon-pcihost",
- .qdev.size = sizeof(TyphoonState),
- .qdev.no_user = 1
+static void typhoon_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = typhoon_pcihost_init;
+ dc->no_user = 1;
+}
+
+static TypeInfo typhoon_pcihost_info = {
+ .name = "typhoon-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TyphoonState),
+ .class_init = typhoon_pcihost_class_init,
};
static void typhoon_register(void)
{
- sysbus_register_withprop(&typhoon_pcihost_info);
+ type_register_static(&typhoon_pcihost_info);
}
device_init(typhoon_register);
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 3a1b111455..c7aaa72d07 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -350,7 +350,7 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
sysbus_connect_irq(s, i, pic[i]);
}
- pci_create_simple(d->bus, 0, "pbm");
+ pci_create_simple(d->bus, 0, "pbm-pci");
/* APB secondary busses */
pci_dev = pci_create_multifunction(d->bus, PCI_DEVFN(1, 0), true,
@@ -436,42 +436,68 @@ static int pbm_pci_host_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo pbm_pci_host_info = {
- .qdev.name = "pbm",
- .qdev.size = sizeof(PCIDevice),
- .init = pbm_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_SUN,
- .device_id = PCI_DEVICE_ID_SUN_SABRE,
- .class_id = PCI_CLASS_BRIDGE_HOST,
- .is_bridge = 1,
+static void pbm_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pbm_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_SUN;
+ k->device_id = PCI_DEVICE_ID_SUN_SABRE;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ k->is_bridge = 1;
+}
+
+static TypeInfo pbm_pci_host_info = {
+ .name = "pbm-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = pbm_pci_host_class_init,
};
-static SysBusDeviceInfo pbm_host_info = {
- .qdev.name = "pbm",
- .qdev.size = sizeof(APBState),
- .qdev.reset = pci_pbm_reset,
- .init = pci_pbm_init_device,
+static void pbm_host_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pci_pbm_init_device;
+ dc->reset = pci_pbm_reset;
+}
+
+static TypeInfo pbm_host_info = {
+ .name = "pbm",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(APBState),
+ .class_init = pbm_host_class_init,
};
-static PCIDeviceInfo pbm_pci_bridge_info = {
- .qdev.name = "pbm-bridge",
- .qdev.size = sizeof(PCIBridge),
- .qdev.vmsd = &vmstate_pci_device,
- .qdev.reset = pci_bridge_reset,
- .init = apb_pci_bridge_initfn,
- .exit = pci_bridge_exitfn,
- .vendor_id = PCI_VENDOR_ID_SUN,
- .device_id = PCI_DEVICE_ID_SUN_SIMBA,
- .revision = 0x11,
- .config_write = pci_bridge_write_config,
- .is_bridge = 1,
+static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = apb_pci_bridge_initfn;
+ k->exit = pci_bridge_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_SUN;
+ k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
+ k->revision = 0x11;
+ k->config_write = pci_bridge_write_config;
+ k->is_bridge = 1;
+ dc->reset = pci_bridge_reset;
+ dc->vmsd = &vmstate_pci_device;
+}
+
+static TypeInfo pbm_pci_bridge_info = {
+ .name = "pbm-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBridge),
+ .class_init = pbm_pci_bridge_class_init,
};
static void pbm_register_devices(void)
{
- sysbus_register_withprop(&pbm_host_info);
- pci_qdev_register(&pbm_pci_host_info);
- pci_qdev_register(&pbm_pci_bridge_info);
+ type_register_static(&pbm_host_info);
+ type_register_static(&pbm_pci_host_info);
+ type_register_static(&pbm_pci_bridge_info);
}
device_init(pbm_register_devices)
diff --git a/hw/apic.c b/hw/apic.c
index 9d0f460b58..086c544bf3 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -16,53 +16,13 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>
*/
-#include "hw.h"
+#include "apic_internal.h"
#include "apic.h"
#include "ioapic.h"
-#include "qemu-timer.h"
#include "host-utils.h"
-#include "sysbus.h"
#include "trace.h"
#include "pc.h"
-/* APIC Local Vector Table */
-#define APIC_LVT_TIMER 0
-#define APIC_LVT_THERMAL 1
-#define APIC_LVT_PERFORM 2
-#define APIC_LVT_LINT0 3
-#define APIC_LVT_LINT1 4
-#define APIC_LVT_ERROR 5
-#define APIC_LVT_NB 6
-
-/* APIC delivery modes */
-#define APIC_DM_FIXED 0
-#define APIC_DM_LOWPRI 1
-#define APIC_DM_SMI 2
-#define APIC_DM_NMI 4
-#define APIC_DM_INIT 5
-#define APIC_DM_SIPI 6
-#define APIC_DM_EXTINT 7
-
-/* APIC destination mode */
-#define APIC_DESTMODE_FLAT 0xf
-#define APIC_DESTMODE_CLUSTER 1
-
-#define APIC_TRIGGER_EDGE 0
-#define APIC_TRIGGER_LEVEL 1
-
-#define APIC_LVT_TIMER_PERIODIC (1<<17)
-#define APIC_LVT_MASKED (1<<16)
-#define APIC_LVT_LEVEL_TRIGGER (1<<15)
-#define APIC_LVT_REMOTE_IRR (1<<14)
-#define APIC_INPUT_POLARITY (1<<13)
-#define APIC_SEND_PENDING (1<<12)
-
-#define ESR_ILLEGAL_ADDRESS (1 << 7)
-
-#define APIC_SV_DIRECTED_IO (1<<12)
-#define APIC_SV_ENABLE (1<<8)
-
-#define MAX_APICS 255
#define MAX_APIC_WORDS 8
/* Intel APIC constants: from include/asm/msidef.h */
@@ -75,43 +35,10 @@
#define MSI_ADDR_DEST_ID_SHIFT 12
#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
-#define MSI_ADDR_SIZE 0x100000
-
-typedef struct APICState APICState;
-
-struct APICState {
- SysBusDevice busdev;
- MemoryRegion io_memory;
- void *cpu_env;
- uint32_t apicbase;
- uint8_t id;
- uint8_t arb_id;
- uint8_t tpr;
- uint32_t spurious_vec;
- uint8_t log_dest;
- uint8_t dest_mode;
- uint32_t isr[8]; /* in service register */
- uint32_t tmr[8]; /* trigger mode register */
- uint32_t irr[8]; /* interrupt request register */
- uint32_t lvt[APIC_LVT_NB];
- uint32_t esr; /* error register */
- uint32_t icr[2];
-
- uint32_t divide_conf;
- int count_shift;
- uint32_t initial_count;
- int64_t initial_count_load_time, next_time;
- uint32_t idx;
- QEMUTimer *timer;
- int sipi_vector;
- int wait_for_sipi;
-};
-
-static APICState *local_apics[MAX_APICS + 1];
-static int apic_irq_delivered;
+static APICCommonState *local_apics[MAX_APICS + 1];
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICState *s);
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
+static void apic_update_irq(APICCommonState *s);
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode);
@@ -151,7 +78,7 @@ static inline int get_bit(uint32_t *tab, int index)
return !!(tab[i] & mask);
}
-static void apic_local_deliver(APICState *s, int vector)
+static void apic_local_deliver(APICCommonState *s, int vector)
{
uint32_t lvt = s->lvt[vector];
int trigger_mode;
@@ -185,7 +112,7 @@ static void apic_local_deliver(APICState *s, int vector)
void apic_deliver_pic_intr(DeviceState *d, int level)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
if (level) {
apic_local_deliver(s, APIC_LVT_LINT0);
@@ -205,6 +132,11 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
}
}
+static void apic_external_nmi(APICCommonState *s)
+{
+ apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
#define foreach_apic(apic, deliver_bitmask, code) \
{\
int __i, __j, __mask;\
@@ -227,7 +159,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
uint8_t delivery_mode, uint8_t vector_num,
uint8_t trigger_mode)
{
- APICState *apic_iter;
+ APICCommonState *apic_iter;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
@@ -293,14 +225,8 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
}
-void cpu_set_apic_base(DeviceState *d, uint64_t val)
+static void apic_set_base(APICCommonState *s, uint64_t val)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- trace_cpu_set_apic_base(val);
-
- if (!s)
- return;
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
/* if disabled, cannot be enabled again */
@@ -311,32 +237,12 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
}
}
-uint64_t cpu_get_apic_base(DeviceState *d)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
-
- return s ? s->apicbase : 0;
-}
-
-void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- if (!s)
- return;
s->tpr = (val & 0x0f) << 4;
apic_update_irq(s);
}
-uint8_t cpu_get_apic_tpr(DeviceState *d)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
- return s ? s->tpr >> 4 : 0;
-}
-
/* return -1 if no bit is set */
static int get_highest_priority_int(uint32_t *tab)
{
@@ -349,7 +255,7 @@ static int get_highest_priority_int(uint32_t *tab)
return -1;
}
-static int apic_get_ppr(APICState *s)
+static int apic_get_ppr(APICCommonState *s)
{
int tpr, isrv, ppr;
@@ -365,7 +271,7 @@ static int apic_get_ppr(APICState *s)
return ppr;
}
-static int apic_get_arb_pri(APICState *s)
+static int apic_get_arb_pri(APICCommonState *s)
{
/* XXX: arbitration */
return 0;
@@ -377,7 +283,7 @@ static int apic_get_arb_pri(APICState *s)
* 0 - no interrupt,
* >0 - interrupt number
*/
-static int apic_irq_pending(APICState *s)
+static int apic_irq_pending(APICCommonState *s)
{
int irrv, ppr;
irrv = get_highest_priority_int(s->irr);
@@ -393,7 +299,7 @@ static int apic_irq_pending(APICState *s)
}
/* signal the CPU if an irq is pending */
-static void apic_update_irq(APICState *s)
+static void apic_update_irq(APICCommonState *s)
{
if (!(s->spurious_vec & APIC_SV_ENABLE)) {
return;
@@ -406,25 +312,9 @@ static void apic_update_irq(APICState *s)
}
}
-void apic_reset_irq_delivered(void)
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
{
- trace_apic_reset_irq_delivered(apic_irq_delivered);
-
- apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
- trace_apic_get_irq_delivered(apic_irq_delivered);
-
- return apic_irq_delivered;
-}
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
-{
- apic_irq_delivered += !get_bit(s->irr, vector_num);
-
- trace_apic_set_irq(apic_irq_delivered);
+ apic_report_irq_delivered(!get_bit(s->irr, vector_num));
set_bit(s->irr, vector_num);
if (trigger_mode)
@@ -434,7 +324,7 @@ static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
apic_update_irq(s);
}
-static void apic_eoi(APICState *s)
+static void apic_eoi(APICCommonState *s)
{
int isrv;
isrv = get_highest_priority_int(s->isr);
@@ -449,7 +339,7 @@ static void apic_eoi(APICState *s)
static int apic_find_dest(uint8_t dest)
{
- APICState *apic = local_apics[dest];
+ APICCommonState *apic = local_apics[dest];
int i;
if (apic && apic->id == dest)
@@ -469,7 +359,7 @@ static int apic_find_dest(uint8_t dest)
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode)
{
- APICState *apic_iter;
+ APICCommonState *apic_iter;
int i;
if (dest_mode == 0) {
@@ -503,34 +393,7 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
}
}
-void apic_init_reset(DeviceState *d)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
- int i;
-
- if (!s)
- return;
-
- s->tpr = 0;
- s->spurious_vec = 0xff;
- s->log_dest = 0;
- s->dest_mode = 0xf;
- memset(s->isr, 0, sizeof(s->isr));
- memset(s->tmr, 0, sizeof(s->tmr));
- memset(s->irr, 0, sizeof(s->irr));
- for(i = 0; i < APIC_LVT_NB; i++)
- s->lvt[i] = 1 << 16; /* mask LVT */
- s->esr = 0;
- memset(s->icr, 0, sizeof(s->icr));
- s->divide_conf = 0;
- s->count_shift = 0;
- s->initial_count = 0;
- s->initial_count_load_time = 0;
- s->next_time = 0;
- s->wait_for_sipi = 1;
-}
-
-static void apic_startup(APICState *s, int vector_num)
+static void apic_startup(APICCommonState *s, int vector_num)
{
s->sipi_vector = vector_num;
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
@@ -538,7 +401,7 @@ static void apic_startup(APICState *s, int vector_num)
void apic_sipi(DeviceState *d)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
@@ -552,10 +415,10 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
uint8_t delivery_mode, uint8_t vector_num,
uint8_t trigger_mode)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
uint32_t deliver_bitmask[MAX_APIC_WORDS];
int dest_shorthand = (s->icr[0] >> 18) & 3;
- APICState *apic_iter;
+ APICCommonState *apic_iter;
switch (dest_shorthand) {
case 0:
@@ -598,7 +461,7 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
int apic_get_interrupt(DeviceState *d)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
int intno;
/* if the APIC is installed or enabled, we let the 8259 handle the
@@ -623,7 +486,7 @@ int apic_get_interrupt(DeviceState *d)
int apic_accept_pic_intr(DeviceState *d)
{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
uint32_t lvt0;
if (!s)
@@ -638,7 +501,7 @@ int apic_accept_pic_intr(DeviceState *d)
return 0;
}
-static uint32_t apic_get_current_count(APICState *s)
+static uint32_t apic_get_current_count(APICCommonState *s)
{
int64_t d;
uint32_t val;
@@ -656,34 +519,18 @@ static uint32_t apic_get_current_count(APICState *s)
return val;
}
-static void apic_timer_update(APICState *s, int64_t current_time)
+static void apic_timer_update(APICCommonState *s, int64_t current_time)
{
- int64_t next_time, d;
-
- if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
- d = (current_time - s->initial_count_load_time) >>
- s->count_shift;
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
- if (!s->initial_count)
- goto no_timer;
- d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
- } else {
- if (d >= s->initial_count)
- goto no_timer;
- d = (uint64_t)s->initial_count + 1;
- }
- next_time = s->initial_count_load_time + (d << s->count_shift);
- qemu_mod_timer(s->timer, next_time);
- s->next_time = next_time;
+ if (apic_next_timer(s, current_time)) {
+ qemu_mod_timer(s->timer, s->next_time);
} else {
- no_timer:
qemu_del_timer(s->timer);
}
}
static void apic_timer(void *opaque)
{
- APICState *s = opaque;
+ APICCommonState *s = opaque;
apic_local_deliver(s, APIC_LVT_TIMER);
apic_timer_update(s, s->next_time);
@@ -710,7 +557,7 @@ static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
{
DeviceState *d;
- APICState *s;
+ APICCommonState *s;
uint32_t val;
int index;
@@ -718,7 +565,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
if (!d) {
return 0;
}
- s = DO_UPCAST(APICState, busdev.qdev, d);
+ s = DO_UPCAST(APICCommonState, busdev.qdev, d);
index = (addr >> 4) & 0xff;
switch(index) {
@@ -801,7 +648,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
DeviceState *d;
- APICState *s;
+ APICCommonState *s;
int index = (addr >> 4) & 0xff;
if (addr > 0xfff || !index) {
/* MSI and MMIO APIC are at the same memory location,
@@ -817,7 +664,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
if (!d) {
return;
}
- s = DO_UPCAST(APICState, busdev.qdev, d);
+ s = DO_UPCAST(APICCommonState, busdev.qdev, d);
trace_apic_mem_writel(addr, val);
@@ -890,93 +737,12 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
}
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+static void apic_post_load(APICCommonState *s)
{
- APICState *s = opaque;
- int i;
-
- if (version_id > 2)
- return -EINVAL;
-
- /* XXX: what if the base changes? (registered memory regions) */
- qemu_get_be32s(f, &s->apicbase);
- qemu_get_8s(f, &s->id);
- qemu_get_8s(f, &s->arb_id);
- qemu_get_8s(f, &s->tpr);
- qemu_get_be32s(f, &s->spurious_vec);
- qemu_get_8s(f, &s->log_dest);
- qemu_get_8s(f, &s->dest_mode);
- for (i = 0; i < 8; i++) {
- qemu_get_be32s(f, &s->isr[i]);
- qemu_get_be32s(f, &s->tmr[i]);
- qemu_get_be32s(f, &s->irr[i]);
- }
- for (i = 0; i < APIC_LVT_NB; i++) {
- qemu_get_be32s(f, &s->lvt[i]);
- }
- qemu_get_be32s(f, &s->esr);
- qemu_get_be32s(f, &s->icr[0]);
- qemu_get_be32s(f, &s->icr[1]);
- qemu_get_be32s(f, &s->divide_conf);
- s->count_shift=qemu_get_be32(f);
- qemu_get_be32s(f, &s->initial_count);
- s->initial_count_load_time=qemu_get_be64(f);
- s->next_time=qemu_get_be64(f);
-
- if (version_id >= 2)
- qemu_get_timer(f, s->timer);
- return 0;
-}
-
-static const VMStateDescription vmstate_apic = {
- .name = "apic",
- .version_id = 3,
- .minimum_version_id = 3,
- .minimum_version_id_old = 1,
- .load_state_old = apic_load_old,
- .fields = (VMStateField []) {
- VMSTATE_UINT32(apicbase, APICState),
- VMSTATE_UINT8(id, APICState),
- VMSTATE_UINT8(arb_id, APICState),
- VMSTATE_UINT8(tpr, APICState),
- VMSTATE_UINT32(spurious_vec, APICState),
- VMSTATE_UINT8(log_dest, APICState),
- VMSTATE_UINT8(dest_mode, APICState),
- VMSTATE_UINT32_ARRAY(isr, APICState, 8),
- VMSTATE_UINT32_ARRAY(tmr, APICState, 8),
- VMSTATE_UINT32_ARRAY(irr, APICState, 8),
- VMSTATE_UINT32_ARRAY(lvt, APICState, APIC_LVT_NB),
- VMSTATE_UINT32(esr, APICState),
- VMSTATE_UINT32_ARRAY(icr, APICState, 2),
- VMSTATE_UINT32(divide_conf, APICState),
- VMSTATE_INT32(count_shift, APICState),
- VMSTATE_UINT32(initial_count, APICState),
- VMSTATE_INT64(initial_count_load_time, APICState),
- VMSTATE_INT64(next_time, APICState),
- VMSTATE_TIMER(timer, APICState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void apic_reset(DeviceState *d)
-{
- APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
- int bsp;
-
- bsp = cpu_is_bsp(s->cpu_env);
- s->apicbase = 0xfee00000 |
- (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
-
- apic_init_reset(d);
-
- if (bsp) {
- /*
- * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
- * time typically by BIOS, so PIC interrupt can be delivered to the
- * processor when local APIC is enabled.
- */
- s->lvt[APIC_LVT_LINT0] = 0x700;
+ if (s->timer_expiry != -1) {
+ qemu_mod_timer(s->timer, s->timer_expiry);
+ } else {
+ qemu_del_timer(s->timer);
}
}
@@ -988,41 +754,36 @@ static const MemoryRegionOps apic_io_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int apic_init1(SysBusDevice *dev)
+static void apic_init(APICCommonState *s)
{
- APICState *s = FROM_SYSBUS(APICState, dev);
- static int last_apic_idx;
-
- if (last_apic_idx >= MAX_APICS) {
- return -1;
- }
- memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic",
- MSI_ADDR_SIZE);
- sysbus_init_mmio(dev, &s->io_memory);
+ memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
+ MSI_SPACE_SIZE);
s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
- s->idx = last_apic_idx++;
local_apics[s->idx] = s;
- return 0;
}
-static SysBusDeviceInfo apic_info = {
- .init = apic_init1,
- .qdev.name = "apic",
- .qdev.size = sizeof(APICState),
- .qdev.vmsd = &vmstate_apic,
- .qdev.reset = apic_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("id", APICState, id, -1),
- DEFINE_PROP_PTR("cpu_env", APICState, cpu_env),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void apic_class_init(ObjectClass *klass, void *data)
+{
+ APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+ k->init = apic_init;
+ k->set_base = apic_set_base;
+ k->set_tpr = apic_set_tpr;
+ k->external_nmi = apic_external_nmi;
+ k->post_load = apic_post_load;
+}
+
+static TypeInfo apic_info = {
+ .name = "apic",
+ .instance_size = sizeof(APICCommonState),
+ .parent = TYPE_APIC_COMMON,
+ .class_init = apic_class_init,
};
static void apic_register_devices(void)
{
- sysbus_register_withprop(&apic_info);
+ type_register_static(&apic_info);
}
device_init(apic_register_devices)
diff --git a/hw/apic.h b/hw/apic.h
index a5c910fe0a..a62d83ba9f 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -8,6 +8,7 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
uint8_t vector_num, uint8_t trigger_mode);
int apic_accept_pic_intr(DeviceState *s);
void apic_deliver_pic_intr(DeviceState *s, int level);
+void apic_deliver_nmi(DeviceState *d);
int apic_get_interrupt(DeviceState *s);
void apic_reset_irq_delivered(void);
int apic_get_irq_delivered(void);
diff --git a/hw/apic_common.c b/hw/apic_common.c
new file mode 100644
index 0000000000..26991b4516
--- /dev/null
+++ b/hw/apic_common.c
@@ -0,0 +1,321 @@
+/*
+ * APIC support - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "apic.h"
+#include "apic_internal.h"
+#include "trace.h"
+
+static int apic_irq_delivered;
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+ trace_cpu_set_apic_base(val);
+
+ if (d) {
+ APICCommonState *s = APIC_COMMON(d);
+ APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+ info->set_base(s, val);
+ }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+ if (d) {
+ APICCommonState *s = APIC_COMMON(d);
+ trace_cpu_get_apic_base((uint64_t)s->apicbase);
+ return s->apicbase;
+ } else {
+ trace_cpu_get_apic_base(0);
+ return 0;
+ }
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+ APICCommonState *s;
+ APICCommonClass *info;
+
+ if (!d) {
+ return;
+ }
+
+ s = APIC_COMMON(d);
+ info = APIC_COMMON_GET_CLASS(s);
+
+ info->set_tpr(s, val);
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+ return s ? s->tpr >> 4 : 0;
+}
+
+void apic_report_irq_delivered(int delivered)
+{
+ apic_irq_delivered += delivered;
+
+ trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
+void apic_reset_irq_delivered(void)
+{
+ trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+ apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+ trace_apic_get_irq_delivered(apic_irq_delivered);
+
+ return apic_irq_delivered;
+}
+
+void apic_deliver_nmi(DeviceState *d)
+{
+ APICCommonState *s = APIC_COMMON(d);
+ APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+ info->external_nmi(s);
+}
+
+bool apic_next_timer(APICCommonState *s, int64_t current_time)
+{
+ int64_t d;
+
+ /* We need to store the timer state separately to support APIC
+ * implementations that maintain a non-QEMU timer, e.g. inside the
+ * host kernel. This open-coded state allows us to migrate between
+ * both models. */
+ s->timer_expiry = -1;
+
+ if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+ return false;
+ }
+
+ d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+ if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+ if (!s->initial_count) {
+ return false;
+ }
+ d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+ ((uint64_t)s->initial_count + 1);
+ } else {
+ if (d >= s->initial_count) {
+ return false;
+ }
+ d = (uint64_t)s->initial_count + 1;
+ }
+ s->next_time = s->initial_count_load_time + (d << s->count_shift);
+ s->timer_expiry = s->next_time;
+ return true;
+}
+
+void apic_init_reset(DeviceState *d)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ int i;
+
+ if (!s) {
+ return;
+ }
+ s->tpr = 0;
+ s->spurious_vec = 0xff;
+ s->log_dest = 0;
+ s->dest_mode = 0xf;
+ memset(s->isr, 0, sizeof(s->isr));
+ memset(s->tmr, 0, sizeof(s->tmr));
+ memset(s->irr, 0, sizeof(s->irr));
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ s->lvt[i] = APIC_LVT_MASKED;
+ }
+ s->esr = 0;
+ memset(s->icr, 0, sizeof(s->icr));
+ s->divide_conf = 0;
+ s->count_shift = 0;
+ s->initial_count = 0;
+ s->initial_count_load_time = 0;
+ s->next_time = 0;
+ s->wait_for_sipi = 1;
+
+ if (s->timer) {
+ qemu_del_timer(s->timer);
+ }
+ s->timer_expiry = -1;
+}
+
+static void apic_reset_common(DeviceState *d)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ bool bsp;
+
+ bsp = cpu_is_bsp(s->cpu_env);
+ s->apicbase = 0xfee00000 |
+ (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+ apic_init_reset(d);
+
+ if (bsp) {
+ /*
+ * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+ * time typically by BIOS, so PIC interrupt can be delivered to the
+ * processor when local APIC is enabled.
+ */
+ s->lvt[APIC_LVT_LINT0] = 0x700;
+ }
+}
+
+/* This function is only used for old state version 1 and 2 */
+static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+ APICCommonState *s = opaque;
+ int i;
+
+ if (version_id > 2) {
+ return -EINVAL;
+ }
+
+ /* XXX: what if the base changes? (registered memory regions) */
+ qemu_get_be32s(f, &s->apicbase);
+ qemu_get_8s(f, &s->id);
+ qemu_get_8s(f, &s->arb_id);
+ qemu_get_8s(f, &s->tpr);
+ qemu_get_be32s(f, &s->spurious_vec);
+ qemu_get_8s(f, &s->log_dest);
+ qemu_get_8s(f, &s->dest_mode);
+ for (i = 0; i < 8; i++) {
+ qemu_get_be32s(f, &s->isr[i]);
+ qemu_get_be32s(f, &s->tmr[i]);
+ qemu_get_be32s(f, &s->irr[i]);
+ }
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ qemu_get_be32s(f, &s->lvt[i]);
+ }
+ qemu_get_be32s(f, &s->esr);
+ qemu_get_be32s(f, &s->icr[0]);
+ qemu_get_be32s(f, &s->icr[1]);
+ qemu_get_be32s(f, &s->divide_conf);
+ s->count_shift = qemu_get_be32(f);
+ qemu_get_be32s(f, &s->initial_count);
+ s->initial_count_load_time = qemu_get_be64(f);
+ s->next_time = qemu_get_be64(f);
+
+ if (version_id >= 2) {
+ qemu_get_timer(f, s->timer);
+ }
+ return 0;
+}
+
+static int apic_init_common(SysBusDevice *dev)
+{
+ APICCommonState *s = APIC_COMMON(dev);
+ APICCommonClass *info;
+ static int apic_no;
+
+ if (apic_no >= MAX_APICS) {
+ return -1;
+ }
+ s->idx = apic_no++;
+
+ info = APIC_COMMON_GET_CLASS(s);
+ info->init(s);
+
+ sysbus_init_mmio(&s->busdev, &s->io_memory);
+ return 0;
+}
+
+static int apic_dispatch_post_load(void *opaque, int version_id)
+{
+ APICCommonState *s = APIC_COMMON(opaque);
+ APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
+
+ if (info->post_load) {
+ info->post_load(s);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_apic_common = {
+ .name = "apic",
+ .version_id = 3,
+ .minimum_version_id = 3,
+ .minimum_version_id_old = 1,
+ .load_state_old = apic_load_old,
+ .post_load = apic_dispatch_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(apicbase, APICCommonState),
+ VMSTATE_UINT8(id, APICCommonState),
+ VMSTATE_UINT8(arb_id, APICCommonState),
+ VMSTATE_UINT8(tpr, APICCommonState),
+ VMSTATE_UINT32(spurious_vec, APICCommonState),
+ VMSTATE_UINT8(log_dest, APICCommonState),
+ VMSTATE_UINT8(dest_mode, APICCommonState),
+ VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
+ VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
+ VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
+ VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
+ VMSTATE_UINT32(esr, APICCommonState),
+ VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
+ VMSTATE_UINT32(divide_conf, APICCommonState),
+ VMSTATE_INT32(count_shift, APICCommonState),
+ VMSTATE_UINT32(initial_count, APICCommonState),
+ VMSTATE_INT64(initial_count_load_time, APICCommonState),
+ VMSTATE_INT64(next_time, APICCommonState),
+ VMSTATE_INT64(timer_expiry,
+ APICCommonState), /* open-coded timer state */
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property apic_properties_common[] = {
+ DEFINE_PROP_UINT8("id", APICCommonState, id, -1),
+ DEFINE_PROP_PTR("cpu_env", APICCommonState, cpu_env),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void apic_common_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_apic_common;
+ dc->reset = apic_reset_common;
+ dc->no_user = 1;
+ dc->props = apic_properties_common;
+ sc->init = apic_init_common;
+}
+
+static TypeInfo apic_common_type = {
+ .name = TYPE_APIC_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(APICCommonState),
+ .class_size = sizeof(APICCommonClass),
+ .class_init = apic_common_class_init,
+ .abstract = true,
+};
+
+static void register_devices(void)
+{
+ type_register_static(&apic_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
new file mode 100644
index 0000000000..0cab010717
--- /dev/null
+++ b/hw/apic_internal.h
@@ -0,0 +1,122 @@
+/*
+ * APIC support - internal interfaces
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#ifndef QEMU_APIC_INTERNAL_H
+#define QEMU_APIC_INTERNAL_H
+
+#include "memory.h"
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* APIC Local Vector Table */
+#define APIC_LVT_TIMER 0
+#define APIC_LVT_THERMAL 1
+#define APIC_LVT_PERFORM 2
+#define APIC_LVT_LINT0 3
+#define APIC_LVT_LINT1 4
+#define APIC_LVT_ERROR 5
+#define APIC_LVT_NB 6
+
+/* APIC delivery modes */
+#define APIC_DM_FIXED 0
+#define APIC_DM_LOWPRI 1
+#define APIC_DM_SMI 2
+#define APIC_DM_NMI 4
+#define APIC_DM_INIT 5
+#define APIC_DM_SIPI 6
+#define APIC_DM_EXTINT 7
+
+/* APIC destination mode */
+#define APIC_DESTMODE_FLAT 0xf
+#define APIC_DESTMODE_CLUSTER 1
+
+#define APIC_TRIGGER_EDGE 0
+#define APIC_TRIGGER_LEVEL 1
+
+#define APIC_LVT_TIMER_PERIODIC (1<<17)
+#define APIC_LVT_MASKED (1<<16)
+#define APIC_LVT_LEVEL_TRIGGER (1<<15)
+#define APIC_LVT_REMOTE_IRR (1<<14)
+#define APIC_INPUT_POLARITY (1<<13)
+#define APIC_SEND_PENDING (1<<12)
+
+#define ESR_ILLEGAL_ADDRESS (1 << 7)
+
+#define APIC_SV_DIRECTED_IO (1<<12)
+#define APIC_SV_ENABLE (1<<8)
+
+#define MAX_APICS 255
+
+#define MSI_SPACE_SIZE 0x100000
+
+typedef struct APICCommonState APICCommonState;
+
+#define TYPE_APIC_COMMON "apic-common"
+#define APIC_COMMON(obj) \
+ OBJECT_CHECK(APICCommonState, (obj), TYPE_APIC_COMMON)
+#define APIC_COMMON_CLASS(klass) \
+ OBJECT_CLASS_CHECK(APICCommonClass, (klass), TYPE_APIC_COMMON)
+#define APIC_COMMON_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(APICCommonClass, (obj), TYPE_APIC_COMMON)
+
+typedef struct APICCommonClass
+{
+ SysBusDeviceClass parent_class;
+
+ void (*init)(APICCommonState *s);
+ void (*set_base)(APICCommonState *s, uint64_t val);
+ void (*set_tpr)(APICCommonState *s, uint8_t val);
+ void (*external_nmi)(APICCommonState *s);
+ void (*post_load)(APICCommonState *s);
+} APICCommonClass;
+
+struct APICCommonState {
+ SysBusDevice busdev;
+ MemoryRegion io_memory;
+ void *cpu_env;
+ uint32_t apicbase;
+ uint8_t id;
+ uint8_t arb_id;
+ uint8_t tpr;
+ uint32_t spurious_vec;
+ uint8_t log_dest;
+ uint8_t dest_mode;
+ uint32_t isr[8]; /* in service register */
+ uint32_t tmr[8]; /* trigger mode register */
+ uint32_t irr[8]; /* interrupt request register */
+ uint32_t lvt[APIC_LVT_NB];
+ uint32_t esr; /* error register */
+ uint32_t icr[2];
+
+ uint32_t divide_conf;
+ int count_shift;
+ uint32_t initial_count;
+ int64_t initial_count_load_time;
+ int64_t next_time;
+ int idx;
+ QEMUTimer *timer;
+ int64_t timer_expiry;
+ int sipi_vector;
+ int wait_for_sipi;
+};
+
+void apic_report_irq_delivered(int delivered);
+bool apic_next_timer(APICCommonState *s, int64_t current_time);
+
+#endif /* !QEMU_APIC_INTERNAL_H */
diff --git a/hw/applesmc.c b/hw/applesmc.c
index c47b592747..b06487f70d 100644
--- a/hw/applesmc.c
+++ b/hw/applesmc.c
@@ -220,22 +220,32 @@ static int applesmc_isa_init(ISADevice *dev)
return 0;
}
-static ISADeviceInfo applesmc_isa_info = {
- .qdev.name = "isa-applesmc",
- .qdev.size = sizeof(struct AppleSMCStatus),
- .qdev.reset = qdev_applesmc_isa_reset,
- .init = applesmc_isa_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
- APPLESMC_DEFAULT_IOBASE),
- DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property applesmc_isa_properties[] = {
+ DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase,
+ APPLESMC_DEFAULT_IOBASE),
+ DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void qdev_applesmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = applesmc_isa_init;
+ dc->reset = qdev_applesmc_isa_reset;
+ dc->props = applesmc_isa_properties;
+}
+
+static TypeInfo applesmc_isa_info = {
+ .name = "isa-applesmc",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(struct AppleSMCStatus),
+ .class_init = qdev_applesmc_class_init,
};
static void applesmc_register_devices(void)
{
- isa_qdev_register(&applesmc_isa_info);
+ type_register_static(&applesmc_isa_info);
}
device_init(applesmc_register_devices)
diff --git a/hw/arm-misc.h b/hw/arm-misc.h
index 6e8ae6b02e..5e5204bbf5 100644
--- a/hw/arm-misc.h
+++ b/hw/arm-misc.h
@@ -30,12 +30,29 @@ struct arm_boot_info {
const char *kernel_cmdline;
const char *initrd_filename;
target_phys_addr_t loader_start;
+ /* multicore boards that use the default secondary core boot functions
+ * need to put the address of the secondary boot code, the boot reg,
+ * and the GIC address in the next 3 values, respectively. boards that
+ * have their own boot functions can use these values as they want.
+ */
target_phys_addr_t smp_loader_start;
target_phys_addr_t smp_bootreg_addr;
target_phys_addr_t smp_priv_base;
int nb_cpus;
int board_id;
int (*atag_board)(const struct arm_boot_info *info, void *p);
+ /* multicore boards that use the default secondary core boot functions
+ * can ignore these two function calls. If the default functions won't
+ * work, then write_secondary_boot() should write a suitable blob of
+ * code mimicing the secondary CPU startup process used by the board's
+ * boot loader/boot ROM code, and secondary_cpu_reset_hook() should
+ * perform any necessary CPU reset handling and set the PC for thei
+ * secondary CPUs to point at this boot blob.
+ */
+ void (*write_secondary_boot)(CPUState *env,
+ const struct arm_boot_info *info);
+ void (*secondary_cpu_reset_hook)(CPUState *env,
+ const struct arm_boot_info *info);
/* Used internally by arm_boot.c */
int is_linux;
target_phys_addr_t initrd_size;
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index bc0457e58b..3c0839c4b4 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,11 +10,6 @@
#include "sysbus.h"
#include "qemu-timer.h"
-/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
- (+ 32 internal). However my test chip only exposes/reports 32.
- More importantly Linux falls over if more than 32 are present! */
-#define GIC_NIRQ 64
-
#define NCPU 4
static inline int
@@ -37,6 +32,7 @@ typedef struct mpcore_priv_state {
MemoryRegion iomem;
MemoryRegion container;
DeviceState *mptimer;
+ uint32_t num_irq;
} mpcore_priv_state;
/* Per-CPU private memory mapped IO. */
@@ -132,7 +128,7 @@ static int mpcore_priv_init(SysBusDevice *dev)
{
mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
- gic_init(&s->gic, s->num_cpu);
+ gic_init(&s->gic, s->num_cpu, s->num_irq);
s->mptimer = qdev_create(NULL, "arm_mptimer");
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
qdev_init_nofail(s->mptimer);
@@ -205,30 +201,61 @@ static int realview_mpcore_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo mpcore_rirq_info = {
- .init = realview_mpcore_init,
- .qdev.name = "realview_mpcore",
- .qdev.size = sizeof(mpcore_rirq_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", mpcore_rirq_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property mpcore_rirq_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ /* The ARM11 MPCORE TRM says the on-chip controller may have
+ * anything from 0 to 224 external interrupt IRQ lines (with another
+ * 32 internal). We default to 32+32, which is the number provided by
+ * the ARM11 MPCore test chip in the Realview Versatile Express
+ * coretile. Other boards may differ and should set this property
+ * appropriately. Some Linux kernels may not boot if the hardware
+ * has more IRQ lines than the kernel expects.
+ */
+ DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo mpcore_priv_info = {
- .init = mpcore_priv_init,
- .qdev.name = "arm11mpcore_priv",
- .qdev.size = sizeof(mpcore_priv_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void mpcore_rirq_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = realview_mpcore_init;
+ dc->props = mpcore_rirq_properties;
+}
+
+static TypeInfo mpcore_rirq_info = {
+ .name = "realview_mpcore",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mpcore_rirq_state),
+ .class_init = mpcore_rirq_class_init,
+};
+
+static Property mpcore_priv_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mpcore_priv_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mpcore_priv_init;
+ dc->props = mpcore_priv_properties;
+}
+
+static TypeInfo mpcore_priv_info = {
+ .name = "arm11mpcore_priv",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mpcore_priv_state),
+ .class_init = mpcore_priv_class_init,
};
static void arm11mpcore_register_devices(void)
{
- sysbus_register_withprop(&mpcore_rirq_info);
- sysbus_register_withprop(&mpcore_priv_info);
+ type_register_static(&mpcore_rirq_info);
+ type_register_static(&mpcore_priv_info);
}
device_init(arm11mpcore_register_devices)
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index bf509a8eb9..5f163fda02 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -20,16 +20,28 @@
/* The worlds second smallest bootloader. Set r0-r2, then jump to kernel. */
static uint32_t bootloader[] = {
0xe3a00000, /* mov r0, #0 */
- 0xe3a01000, /* mov r1, #0x?? */
- 0xe3811c00, /* orr r1, r1, #0x??00 */
- 0xe59f2000, /* ldr r2, [pc, #0] */
- 0xe59ff000, /* ldr pc, [pc, #0] */
+ 0xe59f1004, /* ldr r1, [pc, #4] */
+ 0xe59f2004, /* ldr r2, [pc, #4] */
+ 0xe59ff004, /* ldr pc, [pc, #4] */
+ 0, /* Board ID */
0, /* Address of kernel args. Set by integratorcp_init. */
0 /* Kernel entry point. Set by integratorcp_init. */
};
-/* Entry point for secondary CPUs. Enable interrupt controller and
- Issue WFI until start address is written to system controller. */
+/* Handling for secondary CPU boot in a multicore system.
+ * Unlike the uniprocessor/primary CPU boot, this is platform
+ * dependent. The default code here is based on the secondary
+ * CPU boot protocol used on realview/vexpress boards, with
+ * some parameterisation to increase its flexibility.
+ * QEMU platform models for which this code is not appropriate
+ * should override write_secondary_boot and secondary_cpu_reset_hook
+ * instead.
+ *
+ * This code enables the interrupt controllers for the secondary
+ * CPUs and then puts all the secondary CPUs into a loop waiting
+ * for an interprocessor interrupt and polling a configurable
+ * location for the kernel secondary CPU entry point.
+ */
static uint32_t smpboot[] = {
0xe59f201c, /* ldr r2, privbase */
0xe59f001c, /* ldr r0, startaddr */
@@ -44,6 +56,26 @@ static uint32_t smpboot[] = {
0 /* bootreg: Boot register address is held here */
};
+static void default_write_secondary(CPUState *env,
+ const struct arm_boot_info *info)
+{
+ int n;
+ smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
+ smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
+ for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ smpboot[n] = tswap32(smpboot[n]);
+ }
+ rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
+ info->smp_loader_start);
+}
+
+static void default_reset_secondary(CPUState *env,
+ const struct arm_boot_info *info)
+{
+ stl_phys_notdirty(info->smp_bootreg_addr, 0);
+ env->regs[15] = info->smp_loader_start;
+}
+
#define WRITE_WORD(p, value) do { \
stl_phys_notdirty(p, value); \
p += 4; \
@@ -197,8 +229,7 @@ static void do_cpu_reset(void *opaque)
info->loader_start);
}
} else {
- stl_phys_notdirty(info->smp_bootreg_addr, 0);
- env->regs[15] = info->smp_loader_start;
+ info->secondary_cpu_reset_hook(env, info);
}
}
}
@@ -220,6 +251,13 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
exit(1);
}
+ if (!info->secondary_cpu_reset_hook) {
+ info->secondary_cpu_reset_hook = default_reset_secondary;
+ }
+ if (!info->write_secondary_boot) {
+ info->write_secondary_boot = default_write_secondary;
+ }
+
if (info->nb_cpus == 0)
info->nb_cpus = 1;
@@ -263,8 +301,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
} else {
initrd_size = 0;
}
- bootloader[1] |= info->board_id & 0xff;
- bootloader[2] |= (info->board_id >> 8) & 0xff;
+ bootloader[4] = info->board_id;
bootloader[5] = info->loader_start + KERNEL_ARGS_ADDR;
bootloader[6] = entry;
for (n = 0; n < sizeof(bootloader) / 4; n++) {
@@ -273,13 +310,7 @@ void arm_load_kernel(CPUState *env, struct arm_boot_info *info)
rom_add_blob_fixed("bootloader", bootloader, sizeof(bootloader),
info->loader_start);
if (info->nb_cpus > 1) {
- smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
- smpboot[ARRAY_SIZE(smpboot) - 2] = info->smp_priv_base;
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
- smpboot[n] = tswap32(smpboot[n]);
- }
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
+ info->write_secondary_boot(env, info);
}
info->initrd_size = initrd_size;
}
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 0339cf59fb..cf582a5a14 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -11,6 +11,8 @@
controller, MPCore distributed interrupt controller and ARMv7-M
Nested Vectored Interrupt Controller. */
+/* Maximum number of possible interrupts, determined by the GIC architecture */
+#define GIC_MAXIRQ 1020
//#define DEBUG_GIC
#ifdef DEBUG_GIC
@@ -86,13 +88,13 @@ typedef struct gic_state
int enabled;
int cpu_enabled[NCPU];
- gic_irq_state irq_state[GIC_NIRQ];
+ gic_irq_state irq_state[GIC_MAXIRQ];
#ifndef NVIC
- int irq_target[GIC_NIRQ];
+ int irq_target[GIC_MAXIRQ];
#endif
int priority1[32][NCPU];
- int priority2[GIC_NIRQ - 32];
- int last_active[GIC_NIRQ][NCPU];
+ int priority2[GIC_MAXIRQ - 32];
+ int last_active[GIC_MAXIRQ][NCPU];
int priority_mask[NCPU];
int running_irq[NCPU];
@@ -111,6 +113,7 @@ typedef struct gic_state
struct gic_state *backref[NCPU];
MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
#endif
+ uint32_t num_irq;
} gic_state;
/* TODO: Many places that call this routine could be optimized. */
@@ -133,7 +136,7 @@ static void gic_update(gic_state *s)
}
best_prio = 0x100;
best_irq = 1023;
- for (irq = 0; irq < GIC_NIRQ; irq++) {
+ for (irq = 0; irq < s->num_irq; irq++) {
if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
best_prio = GIC_GET_PRIORITY(irq, cpu);
@@ -222,7 +225,7 @@ static void gic_complete_irq(gic_state * s, int cpu, int irq)
int update = 0;
int cm = 1 << cpu;
DPRINTF("EOI %d\n", irq);
- if (irq >= GIC_NIRQ) {
+ if (irq >= s->num_irq) {
/* This handles two cases:
* 1. If software writes the ID of a spurious interrupt [ie 1023]
* to the GICC_EOIR, the GIC ignores that write.
@@ -279,7 +282,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
if (offset == 0)
return s->enabled;
if (offset == 4)
- return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+ return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
if (offset < 0x08)
return 0;
if (offset >= 0x80) {
@@ -295,7 +298,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
else
irq = (offset - 0x180) * 8;
irq += GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
for (i = 0; i < 8; i++) {
@@ -310,7 +313,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
else
irq = (offset - 0x280) * 8;
irq += GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
mask = (irq < 32) ? cm : ALL_CPU_MASK;
@@ -322,7 +325,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
} else if (offset < 0x400) {
/* Interrupt Active. */
irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
mask = (irq < 32) ? cm : ALL_CPU_MASK;
@@ -334,14 +337,14 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = GIC_GET_PRIORITY(irq, cpu);
#ifndef NVIC
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq >= 29 && irq <= 31) {
res = cm;
@@ -351,7 +354,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
res = 0;
for (i = 0; i < 4; i++) {
@@ -426,7 +429,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x180) {
/* Interrupt Set Enable. */
irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
value = 0xff;
@@ -451,7 +454,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x200) {
/* Interrupt Clear Enable. */
irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
value = 0;
@@ -468,7 +471,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x280) {
/* Interrupt Set Pending. */
irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 16)
irq = 0;
@@ -481,7 +484,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x300) {
/* Interrupt Clear Pending. */
irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
for (i = 0; i < 8; i++) {
/* ??? This currently clears the pending bit for all CPUs, even
@@ -497,7 +500,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0x800) {
/* Interrupt Priority. */
irq = (offset - 0x400) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 32) {
s->priority1[irq][cpu] = value;
@@ -508,7 +511,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0xc00) {
/* Interrupt CPU Target. */
irq = (offset - 0x800) + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 29)
value = 0;
@@ -518,7 +521,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
} else if (offset < 0xf00) {
/* Interrupt Configuration. */
irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
- if (irq >= GIC_NIRQ)
+ if (irq >= s->num_irq)
goto bad_reg;
if (irq < 32)
value |= 0xaa;
@@ -699,7 +702,7 @@ static const MemoryRegionOps gic_cpu_ops = {
static void gic_reset(gic_state *s)
{
int i;
- memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
+ memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
for (i = 0 ; i < NUM_CPU(s); i++) {
s->priority_mask[i] = 0xf0;
s->current_pending[i] = 1023;
@@ -735,17 +738,17 @@ static void gic_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->cpu_enabled[i]);
for (j = 0; j < 32; j++)
qemu_put_be32(f, s->priority1[j][i]);
- for (j = 0; j < GIC_NIRQ; j++)
+ for (j = 0; j < s->num_irq; j++)
qemu_put_be32(f, s->last_active[j][i]);
qemu_put_be32(f, s->priority_mask[i]);
qemu_put_be32(f, s->running_irq[i]);
qemu_put_be32(f, s->running_priority[i]);
qemu_put_be32(f, s->current_pending[i]);
}
- for (i = 0; i < GIC_NIRQ - 32; i++) {
+ for (i = 0; i < s->num_irq - 32; i++) {
qemu_put_be32(f, s->priority2[i]);
}
- for (i = 0; i < GIC_NIRQ; i++) {
+ for (i = 0; i < s->num_irq; i++) {
#ifndef NVIC
qemu_put_be32(f, s->irq_target[i]);
#endif
@@ -772,17 +775,17 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
s->cpu_enabled[i] = qemu_get_be32(f);
for (j = 0; j < 32; j++)
s->priority1[j][i] = qemu_get_be32(f);
- for (j = 0; j < GIC_NIRQ; j++)
+ for (j = 0; j < s->num_irq; j++)
s->last_active[j][i] = qemu_get_be32(f);
s->priority_mask[i] = qemu_get_be32(f);
s->running_irq[i] = qemu_get_be32(f);
s->running_priority[i] = qemu_get_be32(f);
s->current_pending[i] = qemu_get_be32(f);
}
- for (i = 0; i < GIC_NIRQ - 32; i++) {
+ for (i = 0; i < s->num_irq - 32; i++) {
s->priority2[i] = qemu_get_be32(f);
}
- for (i = 0; i < GIC_NIRQ; i++) {
+ for (i = 0; i < s->num_irq; i++) {
#ifndef NVIC
s->irq_target[i] = qemu_get_be32(f);
#endif
@@ -798,9 +801,9 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id)
}
#if NCPU > 1
-static void gic_init(gic_state *s, int num_cpu)
+static void gic_init(gic_state *s, int num_cpu, int num_irq)
#else
-static void gic_init(gic_state *s)
+static void gic_init(gic_state *s, int num_irq)
#endif
{
int i;
@@ -808,7 +811,12 @@ static void gic_init(gic_state *s)
#if NCPU > 1
s->num_cpu = num_cpu;
#endif
- qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
+ s->num_irq = num_irq + GIC_BASE_IRQ;
+ if (s->num_irq > GIC_MAXIRQ) {
+ hw_error("requested %u interrupt lines exceeds GIC maximum %d\n",
+ num_irq, GIC_MAXIRQ);
+ }
+ qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32);
for (i = 0; i < NUM_CPU(s); i++) {
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
diff --git a/hw/arm_l2x0.c b/hw/arm_l2x0.c
index 2faed39f0f..ba26abc6f4 100644
--- a/hw/arm_l2x0.c
+++ b/hw/arm_l2x0.c
@@ -160,22 +160,33 @@ static int l2x0_priv_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo l2x0_info = {
- .init = l2x0_priv_init,
- .qdev.name = "l2x0",
- .qdev.size = sizeof(l2x0_state),
- .qdev.vmsd = &vmstate_l2x0,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = l2x0_priv_reset,
+static Property l2x0_properties[] = {
+ DEFINE_PROP_UINT32("type", l2x0_state, cache_type, 0x1c100100),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void l2x0_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = l2x0_priv_init;
+ dc->vmsd = &vmstate_l2x0;
+ dc->no_user = 1;
+ dc->props = l2x0_properties;
+ dc->reset = l2x0_priv_reset;
+}
+
+static TypeInfo l2x0_info = {
+ .name = "l2x0",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(l2x0_state),
+ .class_init = l2x0_class_init,
};
static void l2x0_register_device(void)
{
- sysbus_register_withprop(&l2x0_info);
+ type_register_static(&l2x0_info);
}
device_init(l2x0_register_device)
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
index 455a0aa55a..5a02365b6f 100644
--- a/hw/arm_mptimer.c
+++ b/hw/arm_mptimer.c
@@ -311,22 +311,33 @@ static const VMStateDescription vmstate_arm_mptimer = {
}
};
-static SysBusDeviceInfo arm_mptimer_info = {
- .init = arm_mptimer_init,
- .qdev.name = "arm_mptimer",
- .qdev.size = sizeof(arm_mptimer_state),
- .qdev.vmsd = &vmstate_arm_mptimer,
- .qdev.reset = arm_mptimer_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property arm_mptimer_properties[] = {
+ DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void arm_mptimer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = arm_mptimer_init;
+ dc->vmsd = &vmstate_arm_mptimer;
+ dc->reset = arm_mptimer_reset;
+ dc->no_user = 1;
+ dc->props = arm_mptimer_properties;
+}
+
+static TypeInfo arm_mptimer_info = {
+ .name = "arm_mptimer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(arm_mptimer_state),
+ .class_init = arm_mptimer_class_init,
};
static void arm_mptimer_register_devices(void)
{
- sysbus_register_withprop(&arm_mptimer_info);
+ type_register_static(&arm_mptimer_info);
}
device_init(arm_mptimer_register_devices)
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 4b88648780..9d257994c0 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -401,22 +401,33 @@ void arm_sysctl_init(uint32_t base, uint32_t sys_id, uint32_t proc_id)
sysbus_mmio_map(sysbus_from_qdev(dev), 0, base);
}
-static SysBusDeviceInfo arm_sysctl_info = {
- .init = arm_sysctl_init1,
- .qdev.name = "realview_sysctl",
- .qdev.size = sizeof(arm_sysctl_state),
- .qdev.vmsd = &vmstate_arm_sysctl,
- .qdev.reset = arm_sysctl_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
- DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property arm_sysctl_properties[] = {
+ DEFINE_PROP_UINT32("sys_id", arm_sysctl_state, sys_id, 0),
+ DEFINE_PROP_UINT32("proc_id", arm_sysctl_state, proc_id, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void arm_sysctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = arm_sysctl_init1;
+ dc->reset = arm_sysctl_reset;
+ dc->vmsd = &vmstate_arm_sysctl;
+ dc->props = arm_sysctl_properties;
+}
+
+static TypeInfo arm_sysctl_info = {
+ .name = "realview_sysctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(arm_sysctl_state),
+ .class_init = arm_sysctl_class_init,
};
static void arm_sysctl_register_devices(void)
{
- sysbus_register_withprop(&arm_sysctl_info);
+ type_register_static(&arm_sysctl_info);
}
device_init(arm_sysctl_register_devices)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 1902f1a7b9..1019d41b3e 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -273,11 +273,8 @@ static int sp804_init(SysBusDevice *dev)
qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
sysbus_init_irq(dev, &s->irq);
- /* The timers are configurable between 32kHz and 1MHz
- * defaulting to 1MHz but overrideable as individual properties */
s->timer[0] = arm_timer_init(s->freq0);
s->timer[1] = arm_timer_init(s->freq1);
-
s->timer[0]->irq = qi[0];
s->timer[1]->irq = qi[1];
memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
@@ -286,17 +283,6 @@ static int sp804_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo sp804_info = {
- .init = sp804_init,
- .qdev.name = "sp804",
- .qdev.size = sizeof(sp804_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
- DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
/* Integrator/CP timer module. */
typedef struct {
@@ -361,10 +347,46 @@ static int icp_pit_init(SysBusDevice *dev)
return 0;
}
+static void icp_pit_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = icp_pit_init;
+}
+
+static TypeInfo icp_pit_info = {
+ .name = "integrator_pit",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(icp_pit_state),
+ .class_init = icp_pit_class_init,
+};
+
+static Property sp804_properties[] = {
+ DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
+ DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sp804_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *k = DEVICE_CLASS(klass);
+
+ sdc->init = sp804_init;
+ k->props = sp804_properties;
+}
+
+static TypeInfo sp804_info = {
+ .name = "sp804",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(sp804_state),
+ .class_init = sp804_class_init,
+};
+
static void arm_timer_register_devices(void)
{
- sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
- sysbus_register_withprop(&sp804_info);
+ type_register_static(&icp_pit_info);
+ type_register_static(&sp804_info);
}
device_init(arm_timer_register_devices)
diff --git a/hw/armv7m.c b/hw/armv7m.c
index 5c7a9502c6..de3d7e0828 100644
--- a/hw/armv7m.c
+++ b/hw/armv7m.c
@@ -245,19 +245,30 @@ qemu_irq *armv7m_init(MemoryRegion *address_space_mem,
return pic;
}
-static SysBusDeviceInfo bitband_info = {
- .init = bitband_init,
- .qdev.name = "ARM,bitband-memory",
- .qdev.size = sizeof(BitBandState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("base", BitBandState, base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property bitband_properties[] = {
+ DEFINE_PROP_UINT32("base", BitBandState, base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void bitband_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = bitband_init;
+ dc->props = bitband_properties;
+}
+
+static TypeInfo bitband_info = {
+ .name = "ARM,bitband-memory",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BitBandState),
+ .class_init = bitband_class_init,
};
static void armv7m_register_devices(void)
{
- sysbus_register_withprop(&bitband_info);
+ type_register_static(&bitband_info);
}
device_init(armv7m_register_devices)
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index bf8c3c50dc..1ed0abc3e7 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -15,9 +15,6 @@
#include "arm-misc.h"
#include "exec-memory.h"
-/* 32 internal lines (16 used for system exceptions) plus 64 external
- interrupt lines. */
-#define GIC_NIRQ 96
#define NCPU 1
#define NVIC 1
@@ -41,6 +38,7 @@ typedef struct {
int64_t tick;
QEMUTimer *timer;
} systick;
+ uint32_t num_irq;
} nvic_state;
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
@@ -125,7 +123,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
switch (offset) {
case 4: /* Interrupt Control Type. */
- return (GIC_NIRQ / 32) - 1;
+ return (s->num_irq / 32) - 1;
case 0x10: /* SysTick Control and Status. */
val = s->systick.control;
s->systick.control &= ~SYSTICK_COUNTFLAG;
@@ -169,7 +167,7 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset)
if (s->gic.current_pending[0] != 1023)
val |= (s->gic.current_pending[0] << 12);
/* ISRPENDING */
- for (irq = 32; irq < GIC_NIRQ; irq++) {
+ for (irq = 32; irq < s->num_irq; irq++) {
if (s->gic.irq_state[irq].pending) {
val |= (1 << 22);
break;
@@ -384,16 +382,44 @@ static int armv7m_nvic_init(SysBusDevice *dev)
{
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
- gic_init(&s->gic);
+ /* note that for the M profile gic_init() takes the number of external
+ * interrupt lines only.
+ */
+ gic_init(&s->gic, s->num_irq);
memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
- vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
return 0;
}
+static Property armv7m_nvic_properties[] = {
+ /* The ARM v7m may have anything from 0 to 496 external interrupt
+ * IRQ lines. We default to 64. Other boards may differ and should
+ * set this property appropriately.
+ */
+ DEFINE_PROP_UINT32("num-irq", nvic_state, num_irq, 64),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = armv7m_nvic_init;
+ dc->vmsd = &vmstate_nvic;
+ dc->props = armv7m_nvic_properties;
+}
+
+static TypeInfo armv7m_nvic_info = {
+ .name = "armv7m_nvic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(nvic_state),
+ .class_init = armv7m_nvic_class_init,
+};
+
static void armv7m_nvic_register_devices(void)
{
- sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init);
+ type_register_static(&armv7m_nvic_info);
}
device_init(armv7m_nvic_register_devices)
diff --git a/hw/bitbang_i2c.c b/hw/bitbang_i2c.c
index 93fb2ed2c8..c9c11823af 100644
--- a/hw/bitbang_i2c.c
+++ b/hw/bitbang_i2c.c
@@ -221,16 +221,25 @@ static int gpio_i2c_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo gpio_i2c_info = {
- .init = gpio_i2c_init,
- .qdev.name = "gpio_i2c",
- .qdev.desc = "Virtual GPIO to I2C bridge",
- .qdev.size = sizeof(GPIOI2CState),
+static void gpio_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = gpio_i2c_init;
+ dc->desc = "Virtual GPIO to I2C bridge";
+}
+
+static TypeInfo gpio_i2c_info = {
+ .name = "gpio_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GPIOI2CState),
+ .class_init = gpio_i2c_class_init,
};
static void bitbang_i2c_register(void)
{
- sysbus_register_withprop(&gpio_i2c_info);
+ type_register_static(&gpio_i2c_info);
}
device_init(bitbang_i2c_register)
diff --git a/hw/boards.h b/hw/boards.h
index 716fd7b1a6..f6d3784cf1 100644
--- a/hw/boards.h
+++ b/hw/boards.h
@@ -22,7 +22,6 @@ typedef struct QEMUMachine {
unsigned int no_serial:1,
no_parallel:1,
use_virtcon:1,
- no_vga:1,
no_floppy:1,
no_cdrom:1,
no_sdcard:1;
diff --git a/hw/bonito.c b/hw/bonito.c
index f2c78377bb..7350a4f9ec 100644
--- a/hw/bonito.c
+++ b/hw/bonito.c
@@ -766,30 +766,47 @@ PCIBus *bonito_init(qemu_irq *pic)
return b;
}
-static PCIDeviceInfo bonito_info = {
- .qdev.name = "Bonito",
- .qdev.desc = "Host bridge",
- .qdev.size = sizeof(PCIBonitoState),
- .qdev.vmsd = &vmstate_bonito,
- .qdev.no_user = 1,
- .init = bonito_initfn,
- /*Bonito North Bridge, built on FPGA, VENDOR_ID/DEVICE_ID are "undefined"*/
- .vendor_id = 0xdf53,
- .device_id = 0x00d5,
- .revision = 0x01,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void bonito_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = bonito_initfn;
+ k->vendor_id = 0xdf53;
+ k->device_id = 0x00d5;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->desc = "Host bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_bonito;
+}
+
+static TypeInfo bonito_info = {
+ .name = "Bonito",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBonitoState),
+ .class_init = bonito_class_init,
};
-static SysBusDeviceInfo bonito_pcihost_info = {
- .init = bonito_pcihost_initfn,
- .qdev.name = "Bonito-pcihost",
- .qdev.size = sizeof(BonitoState),
- .qdev.no_user = 1,
+static void bonito_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = bonito_pcihost_initfn;
+ dc->no_user = 1;
+}
+
+static TypeInfo bonito_pcihost_info = {
+ .name = "Bonito-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(BonitoState),
+ .class_init = bonito_pcihost_class_init,
};
static void bonito_register(void)
{
- sysbus_register_withprop(&bonito_pcihost_info);
- pci_qdev_register(&bonito_info);
+ type_register_static(&bonito_pcihost_info);
+ type_register_static(&bonito_info);
}
device_init(bonito_register);
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 2d2ebce852..9510ed4d94 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -564,29 +564,39 @@ static int emulated_exitfn(CCIDCardState *base)
return 0;
}
-static CCIDCardInfo emulated_card_info = {
- .qdev.name = EMULATED_DEV_NAME,
- .qdev.desc = "emulated smartcard",
- .qdev.size = sizeof(EmulatedState),
- .initfn = emulated_initfn,
- .exitfn = emulated_exitfn,
- .get_atr = emulated_get_atr,
- .apdu_from_guest = emulated_apdu_from_guest,
- .qdev.unplug = qdev_simple_unplug_cb,
- .qdev.props = (Property[]) {
- DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
- DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
- DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
- DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
- DEFINE_PROP_STRING("db", EmulatedState, db),
- DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property emulated_card_properties[] = {
+ DEFINE_PROP_STRING("backend", EmulatedState, backend_str),
+ DEFINE_PROP_STRING("cert1", EmulatedState, cert1),
+ DEFINE_PROP_STRING("cert2", EmulatedState, cert2),
+ DEFINE_PROP_STRING("cert3", EmulatedState, cert3),
+ DEFINE_PROP_STRING("db", EmulatedState, db),
+ DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void emulated_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+ cc->initfn = emulated_initfn;
+ cc->exitfn = emulated_exitfn;
+ cc->get_atr = emulated_get_atr;
+ cc->apdu_from_guest = emulated_apdu_from_guest;
+ dc->desc = "emulated smartcard";
+ dc->props = emulated_card_properties;
+}
+
+static TypeInfo emulated_card_info = {
+ .name = EMULATED_DEV_NAME,
+ .parent = TYPE_CCID_CARD,
+ .instance_size = sizeof(EmulatedState),
+ .class_init = emulated_class_initfn,
};
static void ccid_card_emulated_register_devices(void)
{
- ccid_card_qdev_register(&emulated_card_info);
+ type_register_static(&emulated_card_info);
}
device_init(ccid_card_emulated_register_devices)
diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c
index 9f51c6cb05..a7006ca035 100644
--- a/hw/ccid-card-passthru.c
+++ b/hw/ccid-card-passthru.c
@@ -316,25 +316,36 @@ static VMStateDescription passthru_vmstate = {
}
};
-static CCIDCardInfo passthru_card_info = {
- .qdev.name = PASSTHRU_DEV_NAME,
- .qdev.desc = "passthrough smartcard",
- .qdev.size = sizeof(PassthruState),
- .qdev.vmsd = &passthru_vmstate,
- .initfn = passthru_initfn,
- .exitfn = passthru_exitfn,
- .get_atr = passthru_get_atr,
- .apdu_from_guest = passthru_apdu_from_guest,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", PassthruState, cs),
- DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property passthru_card_properties[] = {
+ DEFINE_PROP_CHR("chardev", PassthruState, cs),
+ DEFINE_PROP_UINT8("debug", PassthruState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void passthru_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ CCIDCardClass *cc = CCID_CARD_CLASS(klass);
+
+ cc->initfn = passthru_initfn;
+ cc->exitfn = passthru_exitfn;
+ cc->get_atr = passthru_get_atr;
+ cc->apdu_from_guest = passthru_apdu_from_guest;
+ dc->desc = "passthrough smartcard";
+ dc->vmsd = &passthru_vmstate;
+ dc->props = passthru_card_properties;
+}
+
+static TypeInfo passthru_card_info = {
+ .name = PASSTHRU_DEV_NAME,
+ .parent = TYPE_CCID_CARD,
+ .instance_size = sizeof(PassthruState),
+ .class_init = passthru_class_initfn,
};
static void ccid_card_passthru_register_devices(void)
{
- ccid_card_qdev_register(&passthru_card_info);
+ type_register_static(&passthru_card_info);
}
device_init(ccid_card_passthru_register_devices)
diff --git a/hw/ccid.h b/hw/ccid.h
index 9e3abe1b4c..6adc745a6d 100644
--- a/hw/ccid.h
+++ b/hw/ccid.h
@@ -15,26 +15,34 @@
typedef struct CCIDCardState CCIDCardState;
typedef struct CCIDCardInfo CCIDCardInfo;
-/*
- * state of the CCID Card device (i.e. hw/ccid-card-*.c)
- */
-struct CCIDCardState {
- DeviceState qdev;
- uint32_t slot; /* For future use with multiple slot reader. */
-};
+#define TYPE_CCID_CARD "ccid-card"
+#define CCID_CARD(obj) \
+ OBJECT_CHECK(CCIDCardState, (obj), TYPE_CCID_CARD)
+#define CCID_CARD_CLASS(klass) \
+ OBJECT_CLASS_CHECK(CCIDCardClass, (klass), TYPE_CCID_CARD)
+#define CCID_CARD_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(CCIDCardClass, (obj), TYPE_CCID_CARD)
/*
* callbacks to be used by the CCID device (hw/usb-ccid.c) to call
* into the smartcard device (hw/ccid-card-*.c)
*/
-struct CCIDCardInfo {
- DeviceInfo qdev;
+typedef struct CCIDCardClass {
+ DeviceClass parent_class;
const uint8_t *(*get_atr)(CCIDCardState *card, uint32_t *len);
void (*apdu_from_guest)(CCIDCardState *card,
const uint8_t *apdu,
uint32_t len);
int (*exitfn)(CCIDCardState *card);
int (*initfn)(CCIDCardState *card);
+} CCIDCardClass;
+
+/*
+ * state of the CCID Card device (i.e. hw/ccid-card-*.c)
+ */
+struct CCIDCardState {
+ DeviceState qdev;
+ uint32_t slot; /* For future use with multiple slot reader. */
};
/*
@@ -46,7 +54,6 @@ void ccid_card_send_apdu_to_guest(CCIDCardState *card,
void ccid_card_card_removed(CCIDCardState *card);
void ccid_card_card_inserted(CCIDCardState *card);
void ccid_card_card_error(CCIDCardState *card, uint64_t error);
-void ccid_card_qdev_register(CCIDCardInfo *card);
/*
* support guest visible insertion/removal of ccid devices based on actual
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index f7b1d3d785..a8e8ab7660 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -250,6 +250,11 @@ typedef struct PCICirrusVGAState {
CirrusVGAState cirrus_vga;
} PCICirrusVGAState;
+typedef struct ISACirrusVGAState {
+ ISADevice dev;
+ CirrusVGAState cirrus_vga;
+} ISACirrusVGAState;
+
static uint8_t rop_to_index[256];
/***************************************
@@ -613,11 +618,7 @@ static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
for (y = 0; y < lines; y++) {
off_cur = off_begin;
off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
- off_cur &= TARGET_PAGE_MASK;
- while (off_cur < off_cur_end) {
- memory_region_set_dirty(&s->vga.vram, off_cur);
- off_cur += TARGET_PAGE_SIZE;
- }
+ memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
off_begin += off_pitch;
}
}
@@ -1895,8 +1896,6 @@ static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
*
* write mode 4/5
*
- * assume TARGET_PAGE_SIZE >= 16
- *
***************************************/
static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
@@ -1918,8 +1917,7 @@ static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
val <<= 1;
dst++;
}
- memory_region_set_dirty(&s->vga.vram, offset);
- memory_region_set_dirty(&s->vga.vram, offset + 7);
+ memory_region_set_dirty(&s->vga.vram, offset, 8);
}
static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
@@ -1943,8 +1941,7 @@ static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
val <<= 1;
dst += 2;
}
- memory_region_set_dirty(&s->vga.vram, offset);
- memory_region_set_dirty(&s->vga.vram, offset + 15);
+ memory_region_set_dirty(&s->vga.vram, offset, 16);
}
/***************************************
@@ -2034,7 +2031,8 @@ static void cirrus_vga_mem_write(void *opaque,
mode = s->vga.gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
*(s->vga.vram_ptr + bank_offset) = mem_value;
- memory_region_set_dirty(&s->vga.vram, bank_offset);
+ memory_region_set_dirty(&s->vga.vram, bank_offset,
+ sizeof(mem_value));
} else {
if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
cirrus_mem_writeb_mode4and5_8bpp(s, mode,
@@ -2166,6 +2164,15 @@ static void cirrus_cursor_invalidate(VGACommonState *s1)
}
}
+#define DEPTH 8
+#include "cirrus_vga_template.h"
+
+#define DEPTH 16
+#include "cirrus_vga_template.h"
+
+#define DEPTH 32
+#include "cirrus_vga_template.h"
+
static void cirrus_cursor_draw_line(VGACommonState *s1, uint8_t *d1, int scr_y)
{
CirrusVGAState *s = container_of(s1, CirrusVGAState, vga);
@@ -2306,7 +2313,7 @@ static void cirrus_linear_write(void *opaque, target_phys_addr_t addr,
mode = s->vga.gr[0x05] & 0x7;
if (mode < 4 || mode > 5 || ((s->vga.gr[0x0B] & 0x4) == 0)) {
*(s->vga.vram_ptr + addr) = (uint8_t) val;
- memory_region_set_dirty(&s->vga.vram, addr);
+ memory_region_set_dirty(&s->vga.vram, addr, 1);
} else {
if ((s->vga.gr[0x0B] & 0x14) != 0x14) {
cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
@@ -2883,24 +2890,45 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci,
*
***************************************/
-DeviceState *isa_cirrus_vga_init(MemoryRegion *system_memory)
+static int vga_initfn(ISADevice *dev)
{
- CirrusVGAState *s;
-
- s = g_malloc0(sizeof(CirrusVGAState));
-
- vga_common_init(&s->vga, VGA_RAM_SIZE);
- cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0, system_memory);
- s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate,
- s->vga.screen_dump, s->vga.text_update,
- &s->vga);
- vmstate_register(NULL, 0, &vmstate_cirrus_vga, s);
+ ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev);
+ VGACommonState *s = &d->cirrus_vga.vga;
+
+ vga_common_init(s, VGA_RAM_SIZE);
+ cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0,
+ isa_address_space(dev));
+ s->ds = graphic_console_init(s->update, s->invalidate,
+ s->screen_dump, s->text_update,
+ s);
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
/* XXX ISA-LFB support */
/* FIXME not qdev yet */
- return NULL;
+ return 0;
+}
+
+static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+ ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_cirrus_vga;
+ k->init = vga_initfn;
}
+static TypeInfo isa_cirrus_vga_info = {
+ .name = "isa-cirrus-vga",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISACirrusVGAState),
+ .class_init = isa_cirrus_vga_class_init,
+};
+
+static void isa_cirrus_vga_register(void)
+{
+ type_register_static(&isa_cirrus_vga_info);
+}
+device_init(isa_cirrus_vga_register)
+
/***************************************
*
* PCI bus support
@@ -2911,8 +2939,8 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
{
PCICirrusVGAState *d = DO_UPCAST(PCICirrusVGAState, dev, dev);
CirrusVGAState *s = &d->cirrus_vga;
- PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->qdev.info);
- int16_t device_id = info->device_id;
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
+ int16_t device_id = pc->device_id;
/* setup VGA */
vga_common_init(&s->vga, VGA_RAM_SIZE);
@@ -2946,21 +2974,30 @@ DeviceState *pci_cirrus_vga_init(PCIBus *bus)
return &pci_create_simple(bus, -1, "cirrus-vga")->qdev;
}
-static PCIDeviceInfo cirrus_vga_info = {
- .qdev.name = "cirrus-vga",
- .qdev.desc = "Cirrus CLGD 54xx VGA",
- .qdev.size = sizeof(PCICirrusVGAState),
- .qdev.vmsd = &vmstate_pci_cirrus_vga,
- .no_hotplug = 1,
- .init = pci_cirrus_vga_initfn,
- .romfile = VGABIOS_CIRRUS_FILENAME,
- .vendor_id = PCI_VENDOR_ID_CIRRUS,
- .device_id = CIRRUS_ID_CLGD5446,
- .class_id = PCI_CLASS_DISPLAY_VGA,
+static void cirrus_vga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_cirrus_vga_initfn;
+ k->romfile = VGABIOS_CIRRUS_FILENAME;
+ k->vendor_id = PCI_VENDOR_ID_CIRRUS;
+ k->device_id = CIRRUS_ID_CLGD5446;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->desc = "Cirrus CLGD 54xx VGA";
+ dc->vmsd = &vmstate_pci_cirrus_vga;
+}
+
+static TypeInfo cirrus_vga_info = {
+ .name = "cirrus-vga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCICirrusVGAState),
+ .class_init = cirrus_vga_class_init,
};
static void cirrus_vga_register(void)
{
- pci_qdev_register(&cirrus_vga_info);
+ type_register_static(&cirrus_vga_info);
}
device_init(cirrus_vga_register);
diff --git a/hw/cirrus_vga_template.h b/hw/cirrus_vga_template.h
new file mode 100644
index 0000000000..3b28280588
--- /dev/null
+++ b/hw/cirrus_vga_template.h
@@ -0,0 +1,102 @@
+/*
+ * QEMU Cirrus VGA Emulator templates
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if DEPTH == 8
+#define BPP 1
+#elif DEPTH == 15 || DEPTH == 16
+#define BPP 2
+#elif DEPTH == 32
+#define BPP 4
+#else
+#error unsupported depth
+#endif
+
+static void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
+ const uint8_t *src1,
+ int poffset, int w,
+ unsigned int color0,
+ unsigned int color1,
+ unsigned int color_xor)
+{
+ const uint8_t *plane0, *plane1;
+ int x, b0, b1;
+ uint8_t *d;
+
+ d = d1;
+ plane0 = src1;
+ plane1 = src1 + poffset;
+ for (x = 0; x < w; x++) {
+ b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
+ b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
+#if DEPTH == 8
+ switch (b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ d[0] ^= color_xor;
+ break;
+ case 2:
+ d[0] = color0;
+ break;
+ case 3:
+ d[0] = color1;
+ break;
+ }
+#elif DEPTH == 16
+ switch (b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ ((uint16_t *)d)[0] ^= color_xor;
+ break;
+ case 2:
+ ((uint16_t *)d)[0] = color0;
+ break;
+ case 3:
+ ((uint16_t *)d)[0] = color1;
+ break;
+ }
+#elif DEPTH == 32
+ switch (b0 | (b1 << 1)) {
+ case 0:
+ break;
+ case 1:
+ ((uint32_t *)d)[0] ^= color_xor;
+ break;
+ case 2:
+ ((uint32_t *)d)[0] = color0;
+ break;
+ case 3:
+ ((uint32_t *)d)[0] = color1;
+ break;
+ }
+#else
+#error unsupported depth
+#endif
+ d += BPP;
+ }
+}
+
+#undef DEPTH
+#undef BPP
diff --git a/hw/container.c b/hw/container.c
deleted file mode 100644
index 9cbf3992c4..0000000000
--- a/hw/container.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "sysbus.h"
-
-static int container_initfn(SysBusDevice *dev)
-{
- return 0;
-}
-
-static SysBusDeviceInfo container_info = {
- .init = container_initfn,
- .qdev.name = "container",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
-};
-
-static void container_init(void)
-{
- sysbus_register_withprop(&container_info);
-}
-
-device_init(container_init);
diff --git a/hw/cs4231.c b/hw/cs4231.c
index 2dfb708fe7..c0badbff5c 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -151,20 +151,31 @@ static int cs4231_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo cs4231_info = {
- .init = cs4231_init1,
- .qdev.name = "SUNW,CS4231",
- .qdev.size = sizeof(CSState),
- .qdev.vmsd = &vmstate_cs4231,
- .qdev.reset = cs_reset,
- .qdev.props = (Property[]) {
- {.name = NULL}
- }
+static Property cs4231_properties[] = {
+ {.name = NULL},
+};
+
+static void cs4231_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = cs4231_init1;
+ dc->reset = cs_reset;
+ dc->vmsd = &vmstate_cs4231;
+ dc->props = cs4231_properties;
+}
+
+static TypeInfo cs4231_info = {
+ .name = "SUNW,CS4231",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(CSState),
+ .class_init = cs4231_class_init,
};
static void cs4231_register_devices(void)
{
- sysbus_register_withprop(&cs4231_info);
+ type_register_static(&cs4231_info);
}
device_init(cs4231_register_devices)
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index dc77a3aa15..ad04ad667c 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -622,13 +622,13 @@ static const VMStateDescription vmstate_cs4231a = {
.pre_load = cs4231a_pre_load,
.post_load = cs4231a_post_load,
.fields = (VMStateField []) {
- VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS),
- VMSTATE_BUFFER(dregs, CSState),
- VMSTATE_INT32(dma_running, CSState),
- VMSTATE_INT32(audio_free, CSState),
- VMSTATE_INT32(transferred, CSState),
- VMSTATE_INT32(aci_counter, CSState),
- VMSTATE_END_OF_LIST()
+ VMSTATE_UINT32_ARRAY (regs, CSState, CS_REGS),
+ VMSTATE_BUFFER (dregs, CSState),
+ VMSTATE_INT32 (dma_running, CSState),
+ VMSTATE_INT32 (audio_free, CSState),
+ VMSTATE_INT32 (transferred, CSState),
+ VMSTATE_INT32 (aci_counter, CSState),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -665,22 +665,32 @@ int cs4231a_init (ISABus *bus)
return 0;
}
-static ISADeviceInfo cs4231a_info = {
- .qdev.name = "cs4231a",
- .qdev.desc = "Crystal Semiconductor CS4231A",
- .qdev.size = sizeof (CSState),
- .qdev.vmsd = &vmstate_cs4231a,
- .init = cs4231a_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534),
- DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
- DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
- DEFINE_PROP_END_OF_LIST (),
- },
+static Property cs4231a_properties[] = {
+ DEFINE_PROP_HEX32 ("iobase", CSState, port, 0x534),
+ DEFINE_PROP_UINT32 ("irq", CSState, irq, 9),
+ DEFINE_PROP_UINT32 ("dma", CSState, dma, 3),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void cs4231a_class_initfn (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+ ic->init = cs4231a_initfn;
+ dc->desc = "Crystal Semiconductor CS4231A";
+ dc->vmsd = &vmstate_cs4231a;
+ dc->props = cs4231a_properties;
+}
+
+static TypeInfo cs4231a_info = {
+ .name = "cs4231a",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof (CSState),
+ .class_init = cs4231a_class_initfn,
};
static void cs4231a_register (void)
{
- isa_qdev_register (&cs4231a_info);
+ type_register_static (&cs4231a_info);
}
device_init (cs4231a_register)
diff --git a/hw/debugcon.c b/hw/debugcon.c
index c9ee6d90b0..3903b2605d 100644
--- a/hw/debugcon.c
+++ b/hw/debugcon.c
@@ -87,21 +87,31 @@ static int debugcon_isa_initfn(ISADevice *dev)
return 0;
}
-static ISADeviceInfo debugcon_isa_info = {
- .qdev.name = "isa-debugcon",
- .qdev.size = sizeof(ISADebugconState),
- .init = debugcon_isa_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
- DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
- DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property debugcon_isa_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISADebugconState, iobase, 0xe9),
+ DEFINE_PROP_CHR("chardev", ISADebugconState, state.chr),
+ DEFINE_PROP_HEX32("readback", ISADebugconState, state.readback, 0xe9),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void debugcon_isa_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = debugcon_isa_initfn;
+ dc->props = debugcon_isa_properties;
+}
+
+static TypeInfo debugcon_isa_info = {
+ .name = "isa-debugcon",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISADebugconState),
+ .class_init = debugcon_isa_class_initfn,
};
static void debugcon_register_devices(void)
{
- isa_qdev_register(&debugcon_isa_info);
+ type_register_static(&debugcon_isa_info);
}
device_init(debugcon_register_devices)
diff --git a/hw/dec_pci.c b/hw/dec_pci.c
index 08d4e06697..a40fbcf3e5 100644
--- a/hw/dec_pci.c
+++ b/hw/dec_pci.c
@@ -50,18 +50,27 @@ static int dec_map_irq(PCIDevice *pci_dev, int irq_num)
return irq_num;
}
-static PCIDeviceInfo dec_21154_pci_bridge_info = {
- .qdev.name = "dec-21154-p2p-bridge",
- .qdev.desc = "DEC 21154 PCI-PCI bridge",
- .qdev.size = sizeof(PCIBridge),
- .qdev.vmsd = &vmstate_pci_device,
- .qdev.reset = pci_bridge_reset,
- .init = pci_bridge_initfn,
- .exit = pci_bridge_exitfn,
- .vendor_id = PCI_VENDOR_ID_DEC,
- .device_id = PCI_DEVICE_ID_DEC_21154,
- .config_write = pci_bridge_write_config,
- .is_bridge = 1,
+static void dec_21154_pci_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_bridge_initfn;
+ k->exit = pci_bridge_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_DEC;
+ k->device_id = PCI_DEVICE_ID_DEC_21154;
+ k->config_write = pci_bridge_write_config;
+ k->is_bridge = 1;
+ dc->desc = "DEC 21154 PCI-PCI bridge";
+ dc->reset = pci_bridge_reset;
+ dc->vmsd = &vmstate_pci_device;
+}
+
+static TypeInfo dec_21154_pci_bridge_info = {
+ .name = "dec-21154-p2p-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIBridge),
+ .class_init = dec_21154_pci_bridge_class_init,
};
PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
@@ -77,7 +86,7 @@ PCIBus *pci_dec_21154_init(PCIBus *parent_bus, int devfn)
return pci_bridge_get_sec_bus(br);
}
-static int pci_dec_21154_init_device(SysBusDevice *dev)
+static int pci_dec_21154_device_init(SysBusDevice *dev)
{
DECState *s;
@@ -98,23 +107,44 @@ static int dec_21154_pci_host_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo dec_21154_pci_host_info = {
- .qdev.name = "dec-21154",
- .qdev.size = sizeof(PCIDevice),
- .init = dec_21154_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_DEC,
- .device_id = PCI_DEVICE_ID_DEC_21154,
- .revision = 0x02,
- .class_id = PCI_CLASS_BRIDGE_PCI,
- .is_bridge = 1,
+static void dec_21154_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = dec_21154_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_DEC;
+ k->device_id = PCI_DEVICE_ID_DEC_21154;
+ k->revision = 0x02;
+ k->class_id = PCI_CLASS_BRIDGE_PCI;
+ k->is_bridge = 1;
+}
+
+static TypeInfo dec_21154_pci_host_info = {
+ .name = "dec-21154",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = dec_21154_pci_host_class_init,
+};
+
+static void pci_dec_21154_device_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pci_dec_21154_device_init;
+}
+
+static TypeInfo pci_dec_21154_device_info = {
+ .name = "dec-21154-sysbus",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(DECState),
+ .class_init = pci_dec_21154_device_class_init,
};
static void dec_register_devices(void)
{
- sysbus_register_dev("dec-21154", sizeof(DECState),
- pci_dec_21154_init_device);
- pci_qdev_register(&dec_21154_pci_host_info);
- pci_qdev_register(&dec_21154_pci_bridge_info);
+ type_register_static(&pci_dec_21154_device_info);
+ type_register_static(&dec_21154_pci_host_info);
+ type_register_static(&dec_21154_pci_bridge_info);
}
device_init(dec_register_devices)
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
index 7aa0832266..539bcebae0 100644
--- a/hw/ds1225y.c
+++ b/hw/ds1225y.c
@@ -134,21 +134,32 @@ static int nvram_sysbus_initfn(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo nvram_sysbus_info = {
- .qdev.name = "ds1225y",
- .qdev.size = sizeof(SysBusNvRamState),
- .qdev.vmsd = &vmstate_nvram,
- .init = nvram_sysbus_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
- DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property nvram_sysbus_properties[] = {
+ DEFINE_PROP_UINT32("size", SysBusNvRamState, nvram.chip_size, 0x2000),
+ DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nvram_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = nvram_sysbus_initfn;
+ dc->vmsd = &vmstate_nvram;
+ dc->props = nvram_sysbus_properties;
+}
+
+static TypeInfo nvram_sysbus_info = {
+ .name = "ds1225y",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusNvRamState),
+ .class_init = nvram_sysbus_class_init,
};
static void nvram_register(void)
{
- sysbus_register_withprop(&nvram_sysbus_info);
+ type_register_static(&nvram_sysbus_info);
}
device_init(nvram_register)
diff --git a/hw/ds1338.c b/hw/ds1338.c
index f754cb7cea..b137e13379 100644
--- a/hw/ds1338.c
+++ b/hw/ds1338.c
@@ -13,7 +13,7 @@
#include "i2c.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
time_t offset;
struct tm now;
uint8_t nvram[56];
@@ -21,7 +21,7 @@ typedef struct {
int addr_byte;
} DS1338State;
-static void ds1338_event(i2c_slave *i2c, enum i2c_event event)
+static void ds1338_event(I2CSlave *i2c, enum i2c_event event)
{
DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
@@ -51,7 +51,7 @@ static void ds1338_event(i2c_slave *i2c, enum i2c_event event)
}
}
-static int ds1338_recv(i2c_slave *i2c)
+static int ds1338_recv(I2CSlave *i2c)
{
DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
uint8_t res;
@@ -61,7 +61,7 @@ static int ds1338_recv(i2c_slave *i2c)
return res;
}
-static int ds1338_send(i2c_slave *i2c, uint8_t data)
+static int ds1338_send(I2CSlave *i2c, uint8_t data)
{
DS1338State *s = FROM_I2C_SLAVE(DS1338State, i2c);
if (s->addr_byte) {
@@ -113,23 +113,31 @@ static int ds1338_send(i2c_slave *i2c, uint8_t data)
return 0;
}
-static int ds1338_init(i2c_slave *i2c)
+static int ds1338_init(I2CSlave *i2c)
{
return 0;
}
-static I2CSlaveInfo ds1338_info = {
- .qdev.name = "ds1338",
- .qdev.size = sizeof(DS1338State),
- .init = ds1338_init,
- .event = ds1338_event,
- .recv = ds1338_recv,
- .send = ds1338_send,
+static void ds1338_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = ds1338_init;
+ k->event = ds1338_event;
+ k->recv = ds1338_recv;
+ k->send = ds1338_send;
+}
+
+static TypeInfo ds1338_info = {
+ .name = "ds1338",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(DS1338State),
+ .class_init = ds1338_class_init,
};
static void ds1338_register_devices(void)
{
- i2c_register_slave(&ds1338_info);
+ type_register_static(&ds1338_info);
}
device_init(ds1338_register_devices)
diff --git a/hw/e1000.c b/hw/e1000.c
index a29c944df4..751f79d5ff 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -466,6 +466,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
bytes = split_size;
if (tp->size + bytes > msh)
bytes = msh - tp->size;
+
+ bytes = MIN(sizeof(tp->data) - tp->size, bytes);
pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes);
if ((sz = tp->size + bytes) >= hdr && tp->size < hdr)
memmove(tp->header, tp->data, hdr);
@@ -481,6 +483,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
// context descriptor TSE is not set, while data descriptor TSE is set
DBGOUT(TXERR, "TCP segmentaion Error\n");
} else {
+ split_size = MIN(sizeof(tp->data) - tp->size, split_size);
pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
tp->size += split_size;
}
@@ -1130,6 +1133,11 @@ static void e1000_reset(void *opaque)
memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
d->rxbuf_min_shift = 1;
memset(&d->tx, 0, sizeof d->tx);
+
+ if (d->nic->nc.link_down) {
+ d->mac_reg[STATUS] &= ~E1000_STATUS_LU;
+ d->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
+ }
}
static NetClientInfo net_e1000_info = {
@@ -1174,7 +1182,7 @@ static int pci_e1000_init(PCIDevice *pci_dev)
d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
d->nic = qemu_new_nic(&net_e1000_info, &d->conf,
- d->dev.qdev.info->name, d->dev.qdev.id, d);
+ object_get_typename(OBJECT(d)), d->dev.qdev.id, d);
qemu_format_nic_info_str(&d->nic->nc, macaddr);
@@ -1189,28 +1197,39 @@ static void qdev_e1000_reset(DeviceState *dev)
e1000_reset(d);
}
-static PCIDeviceInfo e1000_info = {
- .qdev.name = "e1000",
- .qdev.desc = "Intel Gigabit Ethernet",
- .qdev.size = sizeof(E1000State),
- .qdev.reset = qdev_e1000_reset,
- .qdev.vmsd = &vmstate_e1000,
- .init = pci_e1000_init,
- .exit = pci_e1000_uninit,
- .romfile = "pxe-e1000.rom",
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = E1000_DEVID,
- .revision = 0x03,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(E1000State, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property e1000_properties[] = {
+ DEFINE_NIC_PROPERTIES(E1000State, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void e1000_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_e1000_init;
+ k->exit = pci_e1000_uninit;
+ k->romfile = "pxe-e1000.rom";
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = E1000_DEVID;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->desc = "Intel Gigabit Ethernet";
+ dc->reset = qdev_e1000_reset;
+ dc->vmsd = &vmstate_e1000;
+ dc->props = e1000_properties;
+}
+
+static TypeInfo e1000_info = {
+ .name = "e1000",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(E1000State),
+ .class_init = e1000_class_init,
};
static void e1000_register_devices(void)
{
- pci_qdev_register(&e1000_info);
+ type_register_static(&e1000_info);
}
device_init(e1000_register_devices)
diff --git a/hw/eccmemctl.c b/hw/eccmemctl.c
index 774346543a..1cf2090c1f 100644
--- a/hw/eccmemctl.c
+++ b/hw/eccmemctl.c
@@ -308,22 +308,33 @@ static int ecc_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo ecc_info = {
- .init = ecc_init1,
- .qdev.name = "eccmemctl",
- .qdev.size = sizeof(ECCState),
- .qdev.vmsd = &vmstate_ecc,
- .qdev.reset = ecc_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("version", ECCState, version, -1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ecc_properties[] = {
+ DEFINE_PROP_HEX32("version", ECCState, version, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ecc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ecc_init1;
+ dc->reset = ecc_reset;
+ dc->vmsd = &vmstate_ecc;
+ dc->props = ecc_properties;
+}
+
+static TypeInfo ecc_info = {
+ .name = "eccmemctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ECCState),
+ .class_init = ecc_class_init,
};
static void ecc_register_devices(void)
{
- sysbus_register_withprop(&ecc_info);
+ type_register_static(&ecc_info);
}
device_init(ecc_register_devices)
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 6a162f607f..843610c933 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -128,7 +128,13 @@
#define DRVR_INT 0x0200 /* Driver generated interrupt. */
typedef struct {
- PCIDeviceInfo pci;
+ const char *name;
+ const char *desc;
+ uint16_t device_id;
+ uint8_t revision;
+ uint16_t subsystem_vendor_id;
+ uint16_t subsystem_id;
+
uint32_t device;
uint8_t stats_size;
bool has_extended_tcb_support;
@@ -318,6 +324,8 @@ static const uint16_t eepro100_mdi_mask[] = {
#define POLYNOMIAL 0x04c11db6
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s);
+
/* From FreeBSD */
/* XXX: optimize */
static unsigned compute_mcast_idx(const uint8_t * ep)
@@ -487,8 +495,9 @@ static void eepro100_fcp_interrupt(EEPRO100State * s)
}
#endif
-static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
+static void e100_pci_reset(EEPRO100State * s)
{
+ E100PCIDeviceInfo *info = eepro100_get_class(s);
uint32_t device = s->device;
uint8_t *pci_conf = s->dev.config;
@@ -508,8 +517,8 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
/* Maximum Latency */
pci_set_byte(pci_conf + PCI_MAX_LAT, 0x18);
- s->stats_size = e100_device->stats_size;
- s->has_extended_tcb_support = e100_device->has_extended_tcb_support;
+ s->stats_size = info->stats_size;
+ s->has_extended_tcb_support = info->has_extended_tcb_support;
switch (device) {
case i82550:
@@ -558,7 +567,7 @@ static void e100_pci_reset(EEPRO100State * s, E100PCIDeviceInfo *e100_device)
}
assert(s->stats_size > 0 && s->stats_size <= sizeof(s->statistics));
- if (e100_device->power_management) {
+ if (info->power_management) {
/* Power Management Capabilities */
int cfg_offset = 0xdc;
int r = pci_add_capability(&s->dev, PCI_CAP_ID_PM,
@@ -1847,14 +1856,13 @@ static NetClientInfo net_eepro100_info = {
static int e100_nic_init(PCIDevice *pci_dev)
{
EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
- E100PCIDeviceInfo *e100_device = DO_UPCAST(E100PCIDeviceInfo, pci.qdev,
- pci_dev->qdev.info);
+ E100PCIDeviceInfo *info = eepro100_get_class(s);
TRACE(OTHER, logout("\n"));
- s->device = e100_device->device;
+ s->device = info->device;
- e100_pci_reset(s, e100_device);
+ e100_pci_reset(s);
/* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
* i82559 and later support 64 or 256 word EEPROM. */
@@ -1878,7 +1886,7 @@ static int e100_nic_init(PCIDevice *pci_dev)
nic_reset(s);
s->nic = qemu_new_nic(&net_eepro100_info, &s->conf,
- pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+ object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
TRACE(OTHER, logout("%s\n", s->nic->nc.info_str));
@@ -1897,156 +1905,203 @@ static int e100_nic_init(PCIDevice *pci_dev)
static E100PCIDeviceInfo e100_devices[] = {
{
- .pci.qdev.name = "i82550",
- .pci.qdev.desc = "Intel i82550 Ethernet",
+ .name = "i82550",
+ .desc = "Intel i82550 Ethernet",
.device = i82550,
/* TODO: check device id. */
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
/* Revision ID: 0x0c, 0x0d, 0x0e. */
- .pci.revision = 0x0e,
+ .revision = 0x0e,
/* TODO: check size of statistical counters. */
.stats_size = 80,
/* TODO: check extended tcb support. */
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82551",
- .pci.qdev.desc = "Intel i82551 Ethernet",
+ .name = "i82551",
+ .desc = "Intel i82551 Ethernet",
.device = i82551,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
/* Revision ID: 0x0f, 0x10. */
- .pci.revision = 0x0f,
+ .revision = 0x0f,
/* TODO: check size of statistical counters. */
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82557a",
- .pci.qdev.desc = "Intel i82557A Ethernet",
+ .name = "i82557a",
+ .desc = "Intel i82557A Ethernet",
.device = i82557A,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x01,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x01,
.power_management = false,
},{
- .pci.qdev.name = "i82557b",
- .pci.qdev.desc = "Intel i82557B Ethernet",
+ .name = "i82557b",
+ .desc = "Intel i82557B Ethernet",
.device = i82557B,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x02,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x02,
.power_management = false,
},{
- .pci.qdev.name = "i82557c",
- .pci.qdev.desc = "Intel i82557C Ethernet",
+ .name = "i82557c",
+ .desc = "Intel i82557C Ethernet",
.device = i82557C,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x03,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x03,
.power_management = false,
},{
- .pci.qdev.name = "i82558a",
- .pci.qdev.desc = "Intel i82558A Ethernet",
+ .name = "i82558a",
+ .desc = "Intel i82558A Ethernet",
.device = i82558A,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x04,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x04,
.stats_size = 76,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82558b",
- .pci.qdev.desc = "Intel i82558B Ethernet",
+ .name = "i82558b",
+ .desc = "Intel i82558B Ethernet",
.device = i82558B,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x05,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x05,
.stats_size = 76,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559a",
- .pci.qdev.desc = "Intel i82559A Ethernet",
+ .name = "i82559a",
+ .desc = "Intel i82559A Ethernet",
.device = i82559A,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x06,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x06,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559b",
- .pci.qdev.desc = "Intel i82559B Ethernet",
+ .name = "i82559b",
+ .desc = "Intel i82559B Ethernet",
.device = i82559B,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
- .pci.revision = 0x07,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
+ .revision = 0x07,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559c",
- .pci.qdev.desc = "Intel i82559C Ethernet",
+ .name = "i82559c",
+ .desc = "Intel i82559C Ethernet",
.device = i82559C,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82557,
+ .device_id = PCI_DEVICE_ID_INTEL_82557,
#if 0
- .pci.revision = 0x08,
+ .revision = 0x08,
#endif
/* TODO: Windows wants revision id 0x0c. */
- .pci.revision = 0x0c,
+ .revision = 0x0c,
#if EEPROM_SIZE > 0
- .pci.subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
- .pci.subsystem_id = 0x0040,
+ .subsystem_vendor_id = PCI_VENDOR_ID_INTEL,
+ .subsystem_id = 0x0040,
#endif
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82559er",
- .pci.qdev.desc = "Intel i82559ER Ethernet",
+ .name = "i82559er",
+ .desc = "Intel i82559ER Ethernet",
.device = i82559ER,
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
- .pci.revision = 0x09,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .revision = 0x09,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
- .pci.qdev.name = "i82562",
- .pci.qdev.desc = "Intel i82562 Ethernet",
+ .name = "i82562",
+ .desc = "Intel i82562 Ethernet",
.device = i82562,
/* TODO: check device id. */
- .pci.device_id = PCI_DEVICE_ID_INTEL_82551IT,
+ .device_id = PCI_DEVICE_ID_INTEL_82551IT,
/* TODO: wrong revision id. */
- .pci.revision = 0x0e,
+ .revision = 0x0e,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
},{
/* Toshiba Tecra 8200. */
- .pci.qdev.name = "i82801",
- .pci.qdev.desc = "Intel i82801 Ethernet",
+ .name = "i82801",
+ .desc = "Intel i82801 Ethernet",
.device = i82801,
- .pci.device_id = 0x2449,
- .pci.revision = 0x03,
+ .device_id = 0x2449,
+ .revision = 0x03,
.stats_size = 80,
.has_extended_tcb_support = true,
.power_management = true,
}
};
+static E100PCIDeviceInfo *eepro100_get_class_by_name(const char *typename)
+{
+ E100PCIDeviceInfo *info = NULL;
+ int i;
+
+ /* This is admittedly awkward but also temporary. QOM allows for
+ * parameterized typing and for subclassing both of which would suitable
+ * handle what's going on here. But class_data is already being used as
+ * a stop-gap hack to allow incremental qdev conversion so we cannot use it
+ * right now. Once we merge the final QOM series, we can come back here and
+ * do this in a much more elegant fashion.
+ */
+ for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
+ if (strcmp(e100_devices[i].name, typename) == 0) {
+ info = &e100_devices[i];
+ break;
+ }
+ }
+ assert(info != NULL);
+
+ return info;
+}
+
+static E100PCIDeviceInfo *eepro100_get_class(EEPRO100State *s)
+{
+ return eepro100_get_class_by_name(object_get_typename(OBJECT(s)));
+}
+
static Property e100_properties[] = {
DEFINE_NIC_PROPERTIES(EEPRO100State, conf),
DEFINE_PROP_END_OF_LIST(),
};
+static void eepro100_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ E100PCIDeviceInfo *info;
+
+ info = eepro100_get_class_by_name(object_class_get_name(klass));
+
+ dc->props = e100_properties;
+ dc->desc = info->desc;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ k->romfile = "pxe-eepro100.rom";
+ k->init = e100_nic_init;
+ k->exit = pci_nic_uninit;
+ k->device_id = info->device_id;
+ k->revision = info->revision;
+ k->subsystem_vendor_id = info->subsystem_vendor_id;
+ k->subsystem_id = info->subsystem_id;
+}
+
static void eepro100_register_devices(void)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(e100_devices); i++) {
- PCIDeviceInfo *pci_dev = &e100_devices[i].pci;
- /* We use the same rom file for all device ids.
- QEMU fixes the device id during rom load. */
- pci_dev->vendor_id = PCI_VENDOR_ID_INTEL;
- pci_dev->class_id = PCI_CLASS_NETWORK_ETHERNET;
- pci_dev->romfile = "pxe-eepro100.rom";
- pci_dev->init = e100_nic_init;
- pci_dev->exit = pci_nic_uninit;
- pci_dev->qdev.props = e100_properties;
- pci_dev->qdev.size = sizeof(EEPRO100State);
- pci_qdev_register(pci_dev);
+ TypeInfo type_info = {};
+ E100PCIDeviceInfo *info = &e100_devices[i];
+
+ type_info.name = info->name;
+ type_info.parent = TYPE_PCI_DEVICE;
+ type_info.class_init = eepro100_class_init;
+ type_info.instance_size = sizeof(EEPRO100State);
+
+ type_register(&type_info);
}
}
diff --git a/hw/empty_slot.c b/hw/empty_slot.c
index 8b734f2c9f..1bc181555f 100644
--- a/hw/empty_slot.c
+++ b/hw/empty_slot.c
@@ -76,15 +76,23 @@ static int empty_slot_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo empty_slot_info = {
- .init = empty_slot_init1,
- .qdev.name = "empty_slot",
- .qdev.size = sizeof(EmptySlot),
+static void empty_slot_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = empty_slot_init1;
+}
+
+static TypeInfo empty_slot_info = {
+ .name = "empty_slot",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(EmptySlot),
+ .class_init = empty_slot_class_init,
};
static void empty_slot_register_devices(void)
{
- sysbus_register_withprop(&empty_slot_info);
+ type_register_static(&empty_slot_info);
}
device_init(empty_slot_register_devices);
diff --git a/hw/es1370.c b/hw/es1370.c
index 6a3ba55f6f..e377c48e49 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -914,7 +914,7 @@ static const MemoryRegionPortio es1370_portio[] = {
{ 0, 0x40 * 4, 1, .read = es1370_readb, },
{ 0, 0x40 * 2, 2, .read = es1370_readw, },
{ 0, 0x40, 4, .read = es1370_readl, },
- PORTIO_END_OF_LIST()
+ PORTIO_END_OF_LIST ()
};
static const MemoryRegionOps es1370_io_ops = {
@@ -928,12 +928,12 @@ static const VMStateDescription vmstate_es1370_channel = {
.minimum_version_id = 2,
.minimum_version_id_old = 2,
.fields = (VMStateField []) {
- VMSTATE_UINT32(shift, struct chan),
- VMSTATE_UINT32(leftover, struct chan),
- VMSTATE_UINT32(scount, struct chan),
- VMSTATE_UINT32(frame_addr, struct chan),
- VMSTATE_UINT32(frame_cnt, struct chan),
- VMSTATE_END_OF_LIST()
+ VMSTATE_UINT32 (shift, struct chan),
+ VMSTATE_UINT32 (leftover, struct chan),
+ VMSTATE_UINT32 (scount, struct chan),
+ VMSTATE_UINT32 (frame_addr, struct chan),
+ VMSTATE_UINT32 (frame_cnt, struct chan),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -973,15 +973,15 @@ static const VMStateDescription vmstate_es1370 = {
.minimum_version_id_old = 2,
.post_load = es1370_post_load,
.fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, ES1370State),
- VMSTATE_STRUCT_ARRAY(chan, ES1370State, NB_CHANNELS, 2,
- vmstate_es1370_channel, struct chan),
- VMSTATE_UINT32(ctl, ES1370State),
- VMSTATE_UINT32(status, ES1370State),
- VMSTATE_UINT32(mempage, ES1370State),
- VMSTATE_UINT32(codec, ES1370State),
- VMSTATE_UINT32(sctl, ES1370State),
- VMSTATE_END_OF_LIST()
+ VMSTATE_PCI_DEVICE (dev, ES1370State),
+ VMSTATE_STRUCT_ARRAY (chan, ES1370State, NB_CHANNELS, 2,
+ vmstate_es1370_channel, struct chan),
+ VMSTATE_UINT32 (ctl, ES1370State),
+ VMSTATE_UINT32 (status, ES1370State),
+ VMSTATE_UINT32 (mempage, ES1370State),
+ VMSTATE_UINT32 (codec, ES1370State),
+ VMSTATE_UINT32 (sctl, ES1370State),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1017,7 +1017,7 @@ static int es1370_initfn (PCIDevice *dev)
return 0;
}
-static int es1370_exitfn(PCIDevice *dev)
+static int es1370_exitfn (PCIDevice *dev)
{
ES1370State *s = DO_UPCAST (ES1370State, dev, dev);
@@ -1031,28 +1031,32 @@ int es1370_init (PCIBus *bus)
return 0;
}
-static PCIDeviceInfo es1370_info = {
- .qdev.name = "ES1370",
- .qdev.desc = "ENSONIQ AudioPCI ES1370",
- .qdev.size = sizeof (ES1370State),
- .qdev.vmsd = &vmstate_es1370,
- .init = es1370_initfn,
- .exit = es1370_exitfn,
- .vendor_id = PCI_VENDOR_ID_ENSONIQ,
- .device_id = PCI_DEVICE_ID_ENSONIQ_ES1370,
- .class_id = PCI_CLASS_MULTIMEDIA_AUDIO,
-#if 1
- .subsystem_vendor_id = 0x4942,
- .subsystem_id = 0x4c4c,
-#else
- .subsystem_vendor_id = 0x1274,
- .subsystem_id = 0x1371,
-#endif
+static void es1370_class_init (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS (klass);
+
+ k->init = es1370_initfn;
+ k->exit = es1370_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_ENSONIQ;
+ k->device_id = PCI_DEVICE_ID_ENSONIQ_ES1370;
+ k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+ k->subsystem_vendor_id = 0x4942;
+ k->subsystem_id = 0x4c4c;
+ dc->desc = "ENSONIQ AudioPCI ES1370";
+ dc->vmsd = &vmstate_es1370;
+}
+
+static TypeInfo es1370_info = {
+ .name = "ES1370",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof (ES1370State),
+ .class_init = es1370_class_init,
};
static void es1370_register (void)
{
- pci_qdev_register (&es1370_info);
+ type_register_static (&es1370_info);
}
device_init (es1370_register);
diff --git a/hw/escc.c b/hw/escc.c
index 81204a633d..9fe282f7b8 100644
--- a/hw/escc.c
+++ b/hw/escc.c
@@ -901,28 +901,39 @@ static int escc_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo escc_info = {
- .init = escc_init1,
- .qdev.name = "escc",
- .qdev.size = sizeof(SerialState),
- .qdev.vmsd = &vmstate_escc,
- .qdev.reset = escc_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0),
- DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0),
- DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
- DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
- DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0),
- DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0),
- DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
- DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property escc_properties[] = {
+ DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0),
+ DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0),
+ DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
+ DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
+ DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0),
+ DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0),
+ DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
+ DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void escc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = escc_init1;
+ dc->reset = escc_reset;
+ dc->vmsd = &vmstate_escc;
+ dc->props = escc_properties;
+}
+
+static TypeInfo escc_info = {
+ .name = "escc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SerialState),
+ .class_init = escc_class_init,
};
static void escc_register_devices(void)
{
- sysbus_register_withprop(&escc_info);
+ type_register_static(&escc_info);
}
device_init(escc_register_devices)
diff --git a/hw/esp.c b/hw/esp.c
index 9551c7846b..2f44386233 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -753,20 +753,31 @@ static int esp_init1(SysBusDevice *dev)
return scsi_bus_legacy_handle_cmdline(&s->bus);
}
-static SysBusDeviceInfo esp_info = {
- .init = esp_init1,
- .qdev.name = "esp",
- .qdev.size = sizeof(ESPState),
- .qdev.vmsd = &vmstate_esp,
- .qdev.reset = esp_hard_reset,
- .qdev.props = (Property[]) {
- {.name = NULL}
- }
+static Property esp_properties[] = {
+ {.name = NULL},
+};
+
+static void esp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = esp_init1;
+ dc->reset = esp_hard_reset;
+ dc->vmsd = &vmstate_esp;
+ dc->props = esp_properties;
+}
+
+static TypeInfo esp_info = {
+ .name = "esp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ESPState),
+ .class_init = esp_class_init,
};
static void esp_register_devices(void)
{
- sysbus_register_withprop(&esp_info);
+ type_register_static(&esp_info);
}
device_init(esp_register_devices)
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
index 5afa55fb29..aefd5778ab 100644
--- a/hw/etraxfs_eth.c
+++ b/hw/etraxfs_eth.c
@@ -605,7 +605,7 @@ static int fs_eth_init(SysBusDevice *dev)
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(s)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
tdk_init(&s->phy);
@@ -613,22 +613,33 @@ static int fs_eth_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo etraxfs_eth_info = {
- .init = fs_eth_init,
- .qdev.name = "etraxfs-eth",
- .qdev.size = sizeof(struct fs_eth),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
- DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
- DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
- DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property etraxfs_eth_properties[] = {
+ DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
+ DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
+ DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
+ DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = fs_eth_init;
+ dc->props = etraxfs_eth_properties;
+}
+
+static TypeInfo etraxfs_eth_info = {
+ .name = "etraxfs-eth",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct fs_eth),
+ .class_init = etraxfs_eth_class_init,
};
static void etraxfs_eth_register(void)
{
- sysbus_register_withprop(&etraxfs_eth_info);
+ type_register_static(&etraxfs_eth_info);
}
device_init(etraxfs_eth_register)
diff --git a/hw/etraxfs_pic.c b/hw/etraxfs_pic.c
index 993d6a8885..33541fcc61 100644
--- a/hw/etraxfs_pic.c
+++ b/hw/etraxfs_pic.c
@@ -151,19 +151,30 @@ static int etraxfs_pic_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo etraxfs_pic_info = {
- .init = etraxfs_pic_init,
- .qdev.name = "etraxfs,pic",
- .qdev.size = sizeof(struct etrax_pic),
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property etraxfs_pic_properties[] = {
+ DEFINE_PROP_PTR("interrupt_vector", struct etrax_pic, interrupt_vector),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = etraxfs_pic_init;
+ dc->props = etraxfs_pic_properties;
+}
+
+static TypeInfo etraxfs_pic_info = {
+ .name = "etraxfs,pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct etrax_pic),
+ .class_init = etraxfs_pic_class_init,
};
static void etraxfs_pic_register(void)
{
- sysbus_register_withprop(&etraxfs_pic_info);
+ type_register_static(&etraxfs_pic_info);
}
device_init(etraxfs_pic_register)
diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c
index 2623dab9d4..567cb8cc2d 100644
--- a/hw/etraxfs_ser.c
+++ b/hw/etraxfs_ser.c
@@ -216,7 +216,7 @@ static int etraxfs_ser_init(SysBusDevice *dev)
memory_region_init_io(&s->mmio, &ser_ops, s, "etraxfs-serial", R_MAX * 4);
sysbus_init_mmio(dev, &s->mmio);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr)
qemu_chr_add_handlers(s->chr,
serial_can_receive, serial_receive,
@@ -224,16 +224,25 @@ static int etraxfs_ser_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo etraxfs_ser_info = {
- .init = etraxfs_ser_init,
- .qdev.name = "etraxfs,serial",
- .qdev.size = sizeof(struct etrax_serial),
- .qdev.reset = etraxfs_ser_reset,
+static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = etraxfs_ser_init;
+ dc->reset = etraxfs_ser_reset;
+}
+
+static TypeInfo etraxfs_ser_info = {
+ .name = "etraxfs,serial",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct etrax_serial),
+ .class_init = etraxfs_ser_class_init,
};
static void etraxfs_serial_register(void)
{
- sysbus_register_withprop(&etraxfs_ser_info);
+ type_register_static(&etraxfs_ser_info);
}
device_init(etraxfs_serial_register)
diff --git a/hw/etraxfs_timer.c b/hw/etraxfs_timer.c
index 2dfdb3063e..b71c5ee9d5 100644
--- a/hw/etraxfs_timer.c
+++ b/hw/etraxfs_timer.c
@@ -329,10 +329,23 @@ static int etraxfs_timer_init(SysBusDevice *dev)
return 0;
}
+static void etraxfs_timer_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = etraxfs_timer_init;
+}
+
+static TypeInfo etraxfs_timer_info = {
+ .name = "etraxfs,timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof (struct etrax_timer),
+ .class_init = etraxfs_timer_class_init,
+};
+
static void etraxfs_timer_register(void)
{
- sysbus_register_dev("etraxfs,timer", sizeof (struct etrax_timer),
- etraxfs_timer_init);
+ type_register_static(&etraxfs_timer_info);
}
device_init(etraxfs_timer_register)
diff --git a/hw/fdc.c b/hw/fdc.c
index 70aa5c7b56..f575a2c9f5 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1959,21 +1959,31 @@ static const VMStateDescription vmstate_isa_fdc ={
}
};
-static ISADeviceInfo isa_fdc_info = {
- .init = isabus_fdc_init1,
- .qdev.name = "isa-fdc",
- .qdev.fw_name = "fdc",
- .qdev.size = sizeof(FDCtrlISABus),
- .qdev.no_user = 1,
- .qdev.vmsd = &vmstate_isa_fdc,
- .qdev.reset = fdctrl_external_reset_isa,
- .qdev.props = (Property[]) {
- DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
- DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
- DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
- DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property isa_fdc_properties[] = {
+ DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].bs),
+ DEFINE_PROP_DRIVE("driveB", FDCtrlISABus, state.drives[1].bs),
+ DEFINE_PROP_INT32("bootindexA", FDCtrlISABus, bootindexA, -1),
+ DEFINE_PROP_INT32("bootindexB", FDCtrlISABus, bootindexB, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isabus_fdc_class_init1(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = isabus_fdc_init1;
+ dc->fw_name = "fdc";
+ dc->no_user = 1;
+ dc->reset = fdctrl_external_reset_isa;
+ dc->vmsd = &vmstate_isa_fdc;
+ dc->props = isa_fdc_properties;
+}
+
+static TypeInfo isa_fdc_info = {
+ .name = "isa-fdc",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(FDCtrlISABus),
+ .class_init = isabus_fdc_class_init1,
};
static const VMStateDescription vmstate_sysbus_fdc ={
@@ -1986,36 +1996,58 @@ static const VMStateDescription vmstate_sysbus_fdc ={
}
};
-static SysBusDeviceInfo sysbus_fdc_info = {
- .init = sysbus_fdc_init1,
- .qdev.name = "sysbus-fdc",
- .qdev.size = sizeof(FDCtrlSysBus),
- .qdev.vmsd = &vmstate_sysbus_fdc,
- .qdev.reset = fdctrl_external_reset_sysbus,
- .qdev.props = (Property[]) {
- DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
- DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property sysbus_fdc_properties[] = {
+ DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].bs),
+ DEFINE_PROP_DRIVE("driveB", FDCtrlSysBus, state.drives[1].bs),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo sun4m_fdc_info = {
- .init = sun4m_fdc_init1,
- .qdev.name = "SUNW,fdtwo",
- .qdev.size = sizeof(FDCtrlSysBus),
- .qdev.vmsd = &vmstate_sysbus_fdc,
- .qdev.reset = fdctrl_external_reset_sysbus,
- .qdev.props = (Property[]) {
- DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void sysbus_fdc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sysbus_fdc_init1;
+ dc->reset = fdctrl_external_reset_sysbus;
+ dc->vmsd = &vmstate_sysbus_fdc;
+ dc->props = sysbus_fdc_properties;
+}
+
+static TypeInfo sysbus_fdc_info = {
+ .name = "sysbus-fdc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FDCtrlSysBus),
+ .class_init = sysbus_fdc_class_init,
+};
+
+static Property sun4m_fdc_properties[] = {
+ DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].bs),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sun4m_fdc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sun4m_fdc_init1;
+ dc->reset = fdctrl_external_reset_sysbus;
+ dc->vmsd = &vmstate_sysbus_fdc;
+ dc->props = sun4m_fdc_properties;
+}
+
+static TypeInfo sun4m_fdc_info = {
+ .name = "SUNW,fdtwo",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FDCtrlSysBus),
+ .class_init = sun4m_fdc_class_init,
};
static void fdc_register_devices(void)
{
- isa_qdev_register(&isa_fdc_info);
- sysbus_register_withprop(&sysbus_fdc_info);
- sysbus_register_withprop(&sun4m_fdc_info);
+ type_register_static(&isa_fdc_info);
+ type_register_static(&sysbus_fdc_info);
+ type_register_static(&sun4m_fdc_info);
}
device_init(fdc_register_devices)
diff --git a/hw/framebuffer.c b/hw/framebuffer.c
index 6bf48dc046..ea122fb266 100644
--- a/hw/framebuffer.c
+++ b/hw/framebuffer.c
@@ -87,15 +87,8 @@ void framebuffer_update_display(
dest += i * dest_row_pitch;
for (; i < rows; i++) {
- target_phys_addr_t dirty_offset;
- dirty = 0;
- dirty_offset = 0;
- while (addr + dirty_offset < TARGET_PAGE_ALIGN(addr + src_width)) {
- dirty |= memory_region_get_dirty(mem, addr + dirty_offset,
+ dirty = memory_region_get_dirty(mem, addr, addr + src_width,
DIRTY_MEMORY_VGA);
- dirty_offset += TARGET_PAGE_SIZE;
- }
-
if (dirty || invalidate) {
fn(opaque, dest, src, cols, dest_col_pitch);
if (first == -1)
diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c
index f9535328f0..6b2f7d1986 100644
--- a/hw/fw_cfg.c
+++ b/hw/fw_cfg.c
@@ -531,23 +531,34 @@ static int fw_cfg_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo fw_cfg_info = {
- .init = fw_cfg_init1,
- .qdev.name = "fw_cfg",
- .qdev.size = sizeof(FWCfgState),
- .qdev.vmsd = &vmstate_fw_cfg,
- .qdev.reset = fw_cfg_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
- DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property fw_cfg_properties[] = {
+ DEFINE_PROP_HEX32("ctl_iobase", FWCfgState, ctl_iobase, -1),
+ DEFINE_PROP_HEX32("data_iobase", FWCfgState, data_iobase, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void fw_cfg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = fw_cfg_init1;
+ dc->no_user = 1;
+ dc->reset = fw_cfg_reset;
+ dc->vmsd = &vmstate_fw_cfg;
+ dc->props = fw_cfg_properties;
+}
+
+static TypeInfo fw_cfg_info = {
+ .name = "fw_cfg",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(FWCfgState),
+ .class_init = fw_cfg_class_init,
};
static void fw_cfg_register_devices(void)
{
- sysbus_register_withprop(&fw_cfg_info);
+ type_register_static(&fw_cfg_info);
}
device_init(fw_cfg_register_devices)
diff --git a/hw/g364fb.c b/hw/g364fb.c
index 33ec149e0f..66d0044c06 100644
--- a/hw/g364fb.c
+++ b/hw/g364fb.c
@@ -62,7 +62,8 @@ typedef struct G364State {
static inline int check_dirty(G364State *s, ram_addr_t page)
{
- return memory_region_get_dirty(&s->mem_vram, page, DIRTY_MEMORY_VGA);
+ return memory_region_get_dirty(&s->mem_vram, page, G364_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
}
static inline void reset_dirty(G364State *s,
@@ -268,12 +269,9 @@ static void g364fb_update_display(void *opaque)
static inline void g364fb_invalidate_display(void *opaque)
{
G364State *s = opaque;
- int i;
s->blanked = 0;
- for (i = 0; i < s->vram_size; i += G364_PAGE_SIZE) {
- memory_region_set_dirty(&s->mem_vram, i);
- }
+ memory_region_set_dirty(&s->mem_vram, 0, s->vram_size);
}
static void g364fb_reset(G364State *s)
@@ -385,7 +383,7 @@ static void g364fb_update_depth(G364State *s)
static void g364_invalidate_cursor_position(G364State *s)
{
- int ymin, ymax, start, end, i;
+ int ymin, ymax, start, end;
/* invalidate only near the cursor */
ymin = s->cursor_position & 0xfff;
@@ -393,9 +391,7 @@ static void g364_invalidate_cursor_position(G364State *s)
start = ymin * ds_get_linesize(s->ds);
end = (ymax + 1) * ds_get_linesize(s->ds);
- for (i = start; i < end; i += G364_PAGE_SIZE) {
- memory_region_set_dirty(&s->mem_vram, i);
- }
+ memory_region_set_dirty(&s->mem_vram, start, end - start);
}
static void g364fb_ctrl_write(void *opaque,
@@ -553,23 +549,34 @@ static void g364fb_sysbus_reset(DeviceState *d)
g364fb_reset(&s->g364);
}
-static SysBusDeviceInfo g364fb_sysbus_info = {
- .init = g364fb_sysbus_init,
- .qdev.name = "sysbus-g364",
- .qdev.desc = "G364 framebuffer",
- .qdev.size = sizeof(G364SysBusState),
- .qdev.vmsd = &vmstate_g364fb,
- .qdev.reset = g364fb_sysbus_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
- 8 * 1024 * 1024),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property g364fb_sysbus_properties[] = {
+ DEFINE_PROP_HEX32("vram_size", G364SysBusState, g364.vram_size,
+ 8 * 1024 * 1024),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void g364fb_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = g364fb_sysbus_init;
+ dc->desc = "G364 framebuffer";
+ dc->reset = g364fb_sysbus_reset;
+ dc->vmsd = &vmstate_g364fb;
+ dc->props = g364fb_sysbus_properties;
+}
+
+static TypeInfo g364fb_sysbus_info = {
+ .name = "sysbus-g364",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(G364SysBusState),
+ .class_init = g364fb_sysbus_class_init,
};
static void g364fb_register(void)
{
- sysbus_register_withprop(&g364fb_sysbus_info);
+ type_register_static(&g364fb_sysbus_info);
}
device_init(g364fb_register);
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 1e529fb5d0..8122baf482 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -71,7 +71,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic,
SysBusDevice *s;
GrackleState *d;
- dev = qdev_create(NULL, "grackle");
+ dev = qdev_create(NULL, "grackle-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
d = FROM_SYSBUS(GrackleState, s);
@@ -121,21 +121,46 @@ static int grackle_pci_host_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo grackle_pci_host_info = {
- .qdev.name = "grackle",
- .qdev.size = sizeof(PCIDevice),
- .init = grackle_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_MOTOROLA,
- .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void grackle_pci_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = grackle_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+ k->device_id = PCI_DEVICE_ID_MOTOROLA_MPC106;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->no_user = 1;
+}
+
+static TypeInfo grackle_pci_info = {
+ .name = "grackle",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = grackle_pci_class_init,
+};
+
+static void pci_grackle_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = pci_grackle_init_device;
+ dc->no_user = 1;
+}
+
+static TypeInfo grackle_pci_host_info = {
+ .name = "grackle-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GrackleState),
+ .class_init = pci_grackle_class_init,
};
static void grackle_register_devices(void)
{
- sysbus_register_dev("grackle", sizeof(GrackleState),
- pci_grackle_init_device);
- pci_qdev_register(&grackle_pci_host_info);
+ type_register_static(&grackle_pci_info);
+ type_register_static(&grackle_pci_host_info);
}
device_init(grackle_register_devices)
diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c
index f8a64e1644..89de2d85ae 100644
--- a/hw/grlib_apbuart.c
+++ b/hw/grlib_apbuart.c
@@ -24,7 +24,6 @@
#include "sysbus.h"
#include "qemu-char.h"
-#include "ptimer.h"
#include "trace.h"
@@ -66,6 +65,8 @@
#define SCALER_OFFSET 0x0C /* not supported */
#define FIFO_DEBUG_OFFSET 0x10 /* not supported */
+#define FIFO_LENGTH 1024
+
typedef struct UART {
SysBusDevice busdev;
MemoryRegion iomem;
@@ -77,21 +78,67 @@ typedef struct UART {
uint32_t receive;
uint32_t status;
uint32_t control;
+
+ /* FIFO */
+ char buffer[FIFO_LENGTH];
+ int len;
+ int current;
} UART;
+static int uart_data_to_read(UART *uart)
+{
+ return uart->current < uart->len;
+}
+
+static char uart_pop(UART *uart)
+{
+ char ret;
+
+ if (uart->len == 0) {
+ uart->status &= ~UART_DATA_READY;
+ return 0;
+ }
+
+ ret = uart->buffer[uart->current++];
+
+ if (uart->current >= uart->len) {
+ /* Flush */
+ uart->len = 0;
+ uart->current = 0;
+ }
+
+ if (!uart_data_to_read(uart)) {
+ uart->status &= ~UART_DATA_READY;
+ }
+
+ return ret;
+}
+
+static void uart_add_to_fifo(UART *uart,
+ const uint8_t *buffer,
+ int length)
+{
+ if (uart->len + length > FIFO_LENGTH) {
+ abort();
+ }
+ memcpy(uart->buffer + uart->len, buffer, length);
+ uart->len += length;
+}
+
static int grlib_apbuart_can_receive(void *opaque)
{
UART *uart = opaque;
- return !!(uart->status & UART_DATA_READY);
+ return FIFO_LENGTH - uart->len;
}
static void grlib_apbuart_receive(void *opaque, const uint8_t *buf, int size)
{
UART *uart = opaque;
- uart->receive = *buf;
- uart->status |= UART_DATA_READY;
+ uart_add_to_fifo(uart, buf, size);
+
+ uart->status |= UART_DATA_READY;
if (uart->control & UART_RECEIVE_INTERRUPT) {
qemu_irq_pulse(uart->irq);
@@ -103,9 +150,39 @@ static void grlib_apbuart_event(void *opaque, int event)
trace_grlib_apbuart_event(event);
}
-static void
-grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
- uint64_t value, unsigned size)
+
+static uint64_t grlib_apbuart_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ UART *uart = opaque;
+
+ addr &= 0xff;
+
+ /* Unit registers */
+ switch (addr) {
+ case DATA_OFFSET:
+ case DATA_OFFSET + 3: /* when only one byte read */
+ return uart_pop(uart);
+
+ case STATUS_OFFSET:
+ /* Read Only */
+ return uart->status;
+
+ case CONTROL_OFFSET:
+ return uart->control;
+
+ case SCALER_OFFSET:
+ /* Not supported */
+ return 0;
+
+ default:
+ trace_grlib_apbuart_readl_unknown(addr);
+ return 0;
+ }
+}
+
+static void grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
{
UART *uart = opaque;
unsigned char c = 0;
@@ -115,6 +192,7 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
/* Unit registers */
switch (addr) {
case DATA_OFFSET:
+ case DATA_OFFSET + 3: /* When only one byte write */
c = value & 0xFF;
qemu_chr_fe_write(uart->chr, &c, 1);
return;
@@ -124,7 +202,7 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
return;
case CONTROL_OFFSET:
- /* Not supported */
+ uart->control = value;
return;
case SCALER_OFFSET:
@@ -138,21 +216,15 @@ grlib_apbuart_write(void *opaque, target_phys_addr_t addr,
trace_grlib_apbuart_writel_unknown(addr, value);
}
-static bool grlib_apbuart_accepts(void *opaque, target_phys_addr_t addr,
- unsigned size, bool is_write)
-{
- return is_write && size == 4;
-}
-
static const MemoryRegionOps grlib_apbuart_ops = {
- .write = grlib_apbuart_write,
- .valid.accepts = grlib_apbuart_accepts,
+ .write = grlib_apbuart_write,
+ .read = grlib_apbuart_read,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static int grlib_apbuart_init(SysBusDevice *dev)
{
- UART *uart = FROM_SYSBUS(typeof(*uart), dev);
+ UART *uart = FROM_SYSBUS(typeof(*uart), dev);
qemu_chr_add_handlers(uart->chr,
grlib_apbuart_can_receive,
@@ -170,19 +242,30 @@ static int grlib_apbuart_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo grlib_gptimer_info = {
- .init = grlib_apbuart_init,
- .qdev.name = "grlib,apbuart",
- .qdev.size = sizeof(UART),
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chrdev", UART, chr),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property grlib_gptimer_properties[] = {
+ DEFINE_PROP_CHR("chrdev", UART, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = grlib_apbuart_init;
+ dc->props = grlib_gptimer_properties;
+}
+
+static TypeInfo grlib_gptimer_info = {
+ .name = "grlib,apbuart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UART),
+ .class_init = grlib_gptimer_class_init,
};
static void grlib_gptimer_register(void)
{
- sysbus_register_withprop(&grlib_gptimer_info);
+ type_register_static(&grlib_gptimer_info);
}
device_init(grlib_gptimer_register)
diff --git a/hw/grlib_gptimer.c b/hw/grlib_gptimer.c
index 9c98a830d7..fb0b236746 100644
--- a/hw/grlib_gptimer.c
+++ b/hw/grlib_gptimer.c
@@ -372,22 +372,33 @@ static int grlib_gptimer_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo grlib_gptimer_info = {
- .init = grlib_gptimer_init,
- .qdev.name = "grlib,gptimer",
- .qdev.reset = grlib_gptimer_reset,
- .qdev.size = sizeof(GPTimerUnit),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
- DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
- DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property grlib_gptimer_properties[] = {
+ DEFINE_PROP_UINT32("frequency", GPTimerUnit, freq_hz, 40000000),
+ DEFINE_PROP_UINT32("irq-line", GPTimerUnit, irq_line, 8),
+ DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_gptimer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = grlib_gptimer_init;
+ dc->reset = grlib_gptimer_reset;
+ dc->props = grlib_gptimer_properties;
+}
+
+static TypeInfo grlib_gptimer_info = {
+ .name = "grlib,gptimer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GPTimerUnit),
+ .class_init = grlib_gptimer_class_init,
};
static void grlib_gptimer_register(void)
{
- sysbus_register_withprop(&grlib_gptimer_info);
+ type_register_static(&grlib_gptimer_info);
}
device_init(grlib_gptimer_register)
diff --git a/hw/grlib_irqmp.c b/hw/grlib_irqmp.c
index 28725563c0..1e5ad826f5 100644
--- a/hw/grlib_irqmp.c
+++ b/hw/grlib_irqmp.c
@@ -354,21 +354,32 @@ static int grlib_irqmp_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo grlib_irqmp_info = {
- .init = grlib_irqmp_init,
- .qdev.name = "grlib,irqmp",
- .qdev.reset = grlib_irqmp_reset,
- .qdev.size = sizeof(IRQMP),
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
- DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property grlib_irqmp_properties[] = {
+ DEFINE_PROP_PTR("set_pil_in", IRQMP, set_pil_in),
+ DEFINE_PROP_PTR("set_pil_in_opaque", IRQMP, set_pil_in_opaque),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void grlib_irqmp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = grlib_irqmp_init;
+ dc->reset = grlib_irqmp_reset;
+ dc->props = grlib_irqmp_properties;
+}
+
+static TypeInfo grlib_irqmp_info = {
+ .name = "grlib,irqmp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IRQMP),
+ .class_init = grlib_irqmp_class_init,
};
static void grlib_irqmp_register(void)
{
- sysbus_register_withprop(&grlib_irqmp_info);
+ type_register_static(&grlib_irqmp_info);
}
device_init(grlib_irqmp_register)
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index 432683acea..e8cd59c3a4 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -1136,21 +1136,42 @@ static int gt64120_pci_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo gt64120_pci_info = {
- .qdev.name = "gt64120_pci",
- .qdev.size = sizeof(PCIDevice),
- .init = gt64120_pci_init,
- .vendor_id = PCI_VENDOR_ID_MARVELL,
- .device_id = PCI_DEVICE_ID_MARVELL_GT6412X,
- .revision = 0x10,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void gt64120_pci_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = gt64120_pci_init;
+ k->vendor_id = PCI_VENDOR_ID_MARVELL;
+ k->device_id = PCI_DEVICE_ID_MARVELL_GT6412X;
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo gt64120_pci_info = {
+ .name = "gt64120_pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = gt64120_pci_class_init,
+};
+
+static void gt64120_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = gt64120_init;
+}
+
+static TypeInfo gt64120_info = {
+ .name = "gt64120",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GT64120State),
+ .class_init = gt64120_class_init,
};
static void gt64120_pci_register_devices(void)
{
- sysbus_register_dev("gt64120", sizeof(GT64120State),
- gt64120_init);
- pci_qdev_register(&gt64120_pci_info);
+ type_register_static(&gt64120_info);
+ type_register_static(&gt64120_pci_info);
}
device_init(gt64120_pci_register_devices)
diff --git a/hw/gus.c b/hw/gus.c
index ab872d8dc5..20547075ec 100644
--- a/hw/gus.c
+++ b/hw/gus.c
@@ -221,14 +221,14 @@ static const VMStateDescription vmstate_gus = {
.minimum_version_id = 2,
.minimum_version_id_old = 2,
.fields = (VMStateField []) {
- VMSTATE_INT32(pos, GUSState),
- VMSTATE_INT32(left, GUSState),
- VMSTATE_INT32(shift, GUSState),
- VMSTATE_INT32(irqs, GUSState),
- VMSTATE_INT32(samples, GUSState),
- VMSTATE_INT64(last_ticks, GUSState),
- VMSTATE_BUFFER(himem, GUSState),
- VMSTATE_END_OF_LIST()
+ VMSTATE_INT32 (pos, GUSState),
+ VMSTATE_INT32 (left, GUSState),
+ VMSTATE_INT32 (shift, GUSState),
+ VMSTATE_INT32 (irqs, GUSState),
+ VMSTATE_INT32 (samples, GUSState),
+ VMSTATE_INT64 (last_ticks, GUSState),
+ VMSTATE_BUFFER (himem, GUSState),
+ VMSTATE_END_OF_LIST ()
}
};
@@ -239,13 +239,13 @@ static const MemoryRegionPortio gus_portio_list1[] = {
{0x006, 10, 2, .read = gus_readw, .write = gus_writew },
{0x100, 8, 1, .read = gus_readb, .write = gus_writeb },
{0x100, 8, 2, .read = gus_readw, .write = gus_writew },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
static const MemoryRegionPortio gus_portio_list2[] = {
{0, 1, 1, .read = gus_readb },
{0, 1, 2, .read = gus_readw },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
static int gus_initfn (ISADevice *dev)
@@ -299,23 +299,33 @@ int GUS_init (ISABus *bus)
return 0;
}
-static ISADeviceInfo gus_info = {
- .qdev.name = "gus",
- .qdev.desc = "Gravis Ultrasound GF1",
- .qdev.size = sizeof (GUSState),
- .qdev.vmsd = &vmstate_gus,
- .init = gus_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
- DEFINE_PROP_HEX32 ("iobase", GUSState, port, 0x240),
- DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
- DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3),
- DEFINE_PROP_END_OF_LIST (),
- },
+static Property gus_properties[] = {
+ DEFINE_PROP_UINT32 ("freq", GUSState, freq, 44100),
+ DEFINE_PROP_HEX32 ("iobase", GUSState, port, 0x240),
+ DEFINE_PROP_UINT32 ("irq", GUSState, emu.gusirq, 7),
+ DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void gus_class_initfn (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+ ic->init = gus_initfn;
+ dc->desc = "Gravis Ultrasound GF1";
+ dc->vmsd = &vmstate_gus;
+ dc->props = gus_properties;
+}
+
+static TypeInfo gus_info = {
+ .name = "gus",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof (GUSState),
+ .class_init = gus_class_initfn,
};
static void gus_register (void)
{
- isa_qdev_register (&gus_info);
+ type_register_static (&gus_info);
}
device_init (gus_register)
diff --git a/hw/hda-audio.c b/hw/hda-audio.c
index 9b089e65b4..152f8e6f13 100644
--- a/hw/hda-audio.c
+++ b/hw/hda-audio.c
@@ -777,7 +777,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
uint32_t i, type;
a->desc = desc;
- a->name = a->hda.qdev.info->name;
+ a->name = object_get_typename(OBJECT(a));
dprint(a, 1, "%s: cad %d\n", __FUNCTION__, a->hda.cad);
AUD_register_card("hda", &a->card);
@@ -906,33 +906,51 @@ static int hda_audio_init_duplex(HDACodecDevice *hda)
return hda_audio_init(hda, &duplex);
}
-static HDACodecDeviceInfo hda_audio_info_output = {
- .qdev.name = "hda-output",
- .qdev.desc = "HDA Audio Codec, output-only",
- .qdev.size = sizeof(HDAAudioState),
- .qdev.vmsd = &vmstate_hda_audio,
- .qdev.props = hda_audio_properties,
- .init = hda_audio_init_output,
- .exit = hda_audio_exit,
- .command = hda_audio_command,
- .stream = hda_audio_stream,
+static void hda_audio_output_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+ k->init = hda_audio_init_output;
+ k->exit = hda_audio_exit;
+ k->command = hda_audio_command;
+ k->stream = hda_audio_stream;
+ dc->desc = "HDA Audio Codec, output-only";
+ dc->vmsd = &vmstate_hda_audio;
+ dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_output_info = {
+ .name = "hda-output",
+ .parent = TYPE_HDA_CODEC_DEVICE,
+ .instance_size = sizeof(HDAAudioState),
+ .class_init = hda_audio_output_class_init,
};
-static HDACodecDeviceInfo hda_audio_info_duplex = {
- .qdev.name = "hda-duplex",
- .qdev.desc = "HDA Audio Codec, duplex",
- .qdev.size = sizeof(HDAAudioState),
- .qdev.vmsd = &vmstate_hda_audio,
- .qdev.props = hda_audio_properties,
- .init = hda_audio_init_duplex,
- .exit = hda_audio_exit,
- .command = hda_audio_command,
- .stream = hda_audio_stream,
+static void hda_audio_duplex_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+ k->init = hda_audio_init_duplex;
+ k->exit = hda_audio_exit;
+ k->command = hda_audio_command;
+ k->stream = hda_audio_stream;
+ dc->desc = "HDA Audio Codec, duplex";
+ dc->vmsd = &vmstate_hda_audio;
+ dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_duplex_info = {
+ .name = "hda-duplex",
+ .parent = TYPE_HDA_CODEC_DEVICE,
+ .instance_size = sizeof(HDAAudioState),
+ .class_init = hda_audio_duplex_class_init,
};
static void hda_audio_register(void)
{
- hda_codec_register(&hda_audio_info_output);
- hda_codec_register(&hda_audio_info_duplex);
+ type_register_static(&hda_audio_output_info);
+ type_register_static(&hda_audio_duplex_info);
}
device_init(hda_audio_register);
diff --git a/hw/highbank.c b/hw/highbank.c
new file mode 100644
index 0000000000..684178ee3e
--- /dev/null
+++ b/hw/highbank.c
@@ -0,0 +1,339 @@
+/*
+ * Calxeda Highbank SoC emulation
+ *
+ * Copyright (c) 2010-2012 Calxeda
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "sysbus.h"
+#include "arm-misc.h"
+#include "primecell.h"
+#include "devices.h"
+#include "loader.h"
+#include "net.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "sysbus.h"
+#include "blockdev.h"
+#include "exec-memory.h"
+
+#define SMP_BOOT_ADDR 0x100
+#define SMP_BOOT_REG 0x40
+#define GIC_BASE_ADDR 0xfff10000
+
+#define NIRQ_GIC 160
+
+/* Board init. */
+static void highbank_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+
+ env->cp15.c15_config_base_address = GIC_BASE_ADDR;
+}
+
+static void hb_write_secondary(CPUState *env, const struct arm_boot_info *info)
+{
+ int n;
+ uint32_t smpboot[] = {
+ 0xee100fb0, /* mrc p15, 0, r0, c0, c0, 5 - read current core id */
+ 0xe210000f, /* ands r0, r0, #0x0f */
+ 0xe3a03040, /* mov r3, #0x40 - jump address is 0x40 + 0x10 * core id */
+ 0xe0830200, /* add r0, r3, r0, lsl #4 */
+ 0xe59f2018, /* ldr r2, privbase */
+ 0xe3a01001, /* mov r1, #1 */
+ 0xe5821100, /* str r1, [r2, #256] */
+ 0xe320f003, /* wfi */
+ 0xe5901000, /* ldr r1, [r0] */
+ 0xe1110001, /* tst r1, r1 */
+ 0x0afffffb, /* beq <wfi> */
+ 0xe12fff11, /* bx r1 */
+ GIC_BASE_ADDR /* privbase: gic address. */
+ };
+ for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
+ smpboot[n] = tswap32(smpboot[n]);
+ }
+ rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot), SMP_BOOT_ADDR);
+}
+
+static void hb_reset_secondary(CPUState *env, const struct arm_boot_info *info)
+{
+ switch (info->nb_cpus) {
+ case 4:
+ stl_phys_notdirty(SMP_BOOT_REG + 0x30, 0);
+ case 3:
+ stl_phys_notdirty(SMP_BOOT_REG + 0x20, 0);
+ case 2:
+ stl_phys_notdirty(SMP_BOOT_REG + 0x10, 0);
+ env->regs[15] = SMP_BOOT_ADDR;
+ break;
+ default:
+ break;
+ }
+}
+
+#define NUM_REGS 0x200
+static void hb_regs_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ uint32_t *regs = opaque;
+
+ if (offset == 0xf00) {
+ if (value == 1 || value == 2) {
+ qemu_system_reset_request();
+ } else if (value == 3) {
+ qemu_system_shutdown_request();
+ }
+ }
+
+ regs[offset/4] = value;
+}
+
+static uint64_t hb_regs_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ uint32_t *regs = opaque;
+ uint32_t value = regs[offset/4];
+
+ if ((offset == 0x100) || (offset == 0x108) || (offset == 0x10C)) {
+ value |= 0x30000000;
+ }
+
+ return value;
+}
+
+static const MemoryRegionOps hb_mem_ops = {
+ .read = hb_regs_read,
+ .write = hb_regs_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+typedef struct {
+ SysBusDevice busdev;
+ MemoryRegion *iomem;
+ uint32_t regs[NUM_REGS];
+} HighbankRegsState;
+
+static VMStateDescription vmstate_highbank_regs = {
+ .name = "highbank-regs",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .minimum_version_id_old = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(regs, HighbankRegsState, NUM_REGS),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static void highbank_regs_reset(DeviceState *dev)
+{
+ SysBusDevice *sys_dev = sysbus_from_qdev(dev);
+ HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, sys_dev);
+
+ s->regs[0x40] = 0x05F20121;
+ s->regs[0x41] = 0x2;
+ s->regs[0x42] = 0x05F30121;
+ s->regs[0x43] = 0x05F40121;
+}
+
+static int highbank_regs_init(SysBusDevice *dev)
+{
+ HighbankRegsState *s = FROM_SYSBUS(HighbankRegsState, dev);
+
+ s->iomem = g_new(MemoryRegion, 1);
+ memory_region_init_io(s->iomem, &hb_mem_ops, s->regs, "highbank_regs",
+ 0x1000);
+ sysbus_init_mmio(dev, s->iomem);
+
+ return 0;
+}
+
+static void highbank_regs_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sbc->init = highbank_regs_init;
+ dc->desc = "Calxeda Highbank registers";
+ dc->vmsd = &vmstate_highbank_regs;
+ dc->reset = highbank_regs_reset;
+}
+
+static TypeInfo highbank_regs_info = {
+ .name = "highbank-regs",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HighbankRegsState),
+ .class_init = highbank_regs_class_init,
+};
+
+static void highbank_regs_register_device(void)
+{
+ type_register_static(&highbank_regs_info);
+}
+
+device_init(highbank_regs_register_device)
+
+static struct arm_boot_info highbank_binfo;
+
+/* ram_size must be set to match the upper bound of memory in the
+ * device tree (linux/arch/arm/boot/dts/highbank.dts), which is
+ * normally 0xff900000 or -m 4089. When running this board on a
+ * 32-bit host, set the reg value of memory to 0xf7ff00000 in the
+ * device tree and pass -m 2047 to QEMU.
+ */
+static void highbank_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ CPUState *env = NULL;
+ DeviceState *dev;
+ SysBusDevice *busdev;
+ qemu_irq *irqp;
+ qemu_irq pic[128];
+ int n;
+ qemu_irq cpu_irq[4];
+ MemoryRegion *sysram;
+ MemoryRegion *dram;
+ MemoryRegion *sysmem;
+ char *sysboot_filename;
+
+ if (!cpu_model) {
+ cpu_model = "cortex-a9";
+ }
+
+ for (n = 0; n < smp_cpus; n++) {
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to find CPU definition\n");
+ exit(1);
+ }
+ irqp = arm_pic_init_cpu(env);
+ cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
+ qemu_register_reset(highbank_cpu_reset, env);
+ }
+
+ sysmem = get_system_memory();
+ dram = g_new(MemoryRegion, 1);
+ memory_region_init_ram(dram, "highbank.dram", ram_size);
+ /* SDRAM at address zero. */
+ memory_region_add_subregion(sysmem, 0, dram);
+
+ sysram = g_new(MemoryRegion, 1);
+ memory_region_init_ram(sysram, "highbank.sysram", 0x8000);
+ memory_region_add_subregion(sysmem, 0xfff88000, sysram);
+ if (bios_name != NULL) {
+ sysboot_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ if (sysboot_filename != NULL) {
+ uint32_t filesize = get_image_size(sysboot_filename);
+ if (load_image_targphys("sysram.bin", 0xfff88000, filesize) < 0) {
+ hw_error("Unable to load %s\n", bios_name);
+ }
+ } else {
+ hw_error("Unable to find %s\n", bios_name);
+ }
+ }
+
+ dev = qdev_create(NULL, "a9mpcore_priv");
+ qdev_prop_set_uint32(dev, "num-cpu", smp_cpus);
+ qdev_prop_set_uint32(dev, "num-irq", NIRQ_GIC);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, GIC_BASE_ADDR);
+ for (n = 0; n < smp_cpus; n++) {
+ sysbus_connect_irq(busdev, n, cpu_irq[n]);
+ }
+
+ for (n = 0; n < 128; n++) {
+ pic[n] = qdev_get_gpio_in(dev, n);
+ }
+
+ dev = qdev_create(NULL, "l2x0");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, 0xfff12000);
+
+ dev = qdev_create(NULL, "sp804");
+ qdev_prop_set_uint32(dev, "freq0", 150000000);
+ qdev_prop_set_uint32(dev, "freq1", 150000000);
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, 0xfff34000);
+ sysbus_connect_irq(busdev, 0, pic[18]);
+ sysbus_create_simple("pl011", 0xfff36000, pic[20]);
+
+ dev = qdev_create(NULL, "highbank-regs");
+ qdev_init_nofail(dev);
+ busdev = sysbus_from_qdev(dev);
+ sysbus_mmio_map(busdev, 0, 0xfff3c000);
+
+ sysbus_create_simple("pl061", 0xfff30000, pic[14]);
+ sysbus_create_simple("pl061", 0xfff31000, pic[15]);
+ sysbus_create_simple("pl061", 0xfff32000, pic[16]);
+ sysbus_create_simple("pl061", 0xfff33000, pic[17]);
+ sysbus_create_simple("pl031", 0xfff35000, pic[19]);
+ sysbus_create_simple("pl022", 0xfff39000, pic[23]);
+
+ sysbus_create_simple("sysbus-ahci", 0xffe08000, pic[83]);
+
+ if (nd_table[0].vlan) {
+ qemu_check_nic_model(&nd_table[0], "xgmac");
+ dev = qdev_create(NULL, "xgmac");
+ qdev_set_nic_properties(dev, &nd_table[0]);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff50000);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[77]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[78]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[79]);
+
+ qemu_check_nic_model(&nd_table[1], "xgmac");
+ dev = qdev_create(NULL, "xgmac");
+ qdev_set_nic_properties(dev, &nd_table[1]);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xfff51000);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[80]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 1, pic[81]);
+ sysbus_connect_irq(sysbus_from_qdev(dev), 2, pic[82]);
+ }
+
+ highbank_binfo.ram_size = ram_size;
+ highbank_binfo.kernel_filename = kernel_filename;
+ highbank_binfo.kernel_cmdline = kernel_cmdline;
+ highbank_binfo.initrd_filename = initrd_filename;
+ /* highbank requires a dtb in order to boot, and the dtb will override
+ * the board ID. The following value is ignored, so set it to -1 to be
+ * clear that the value is meaningless.
+ */
+ highbank_binfo.board_id = -1;
+ highbank_binfo.nb_cpus = smp_cpus;
+ highbank_binfo.loader_start = 0;
+ highbank_binfo.write_secondary_boot = hb_write_secondary;
+ highbank_binfo.secondary_cpu_reset_hook = hb_reset_secondary;
+ arm_load_kernel(first_cpu, &highbank_binfo);
+}
+
+static QEMUMachine highbank_machine = {
+ .name = "highbank",
+ .desc = "Calxeda Highbank (ECX-1000)",
+ .init = highbank_init,
+ .use_scsi = 1,
+ .max_cpus = 4,
+};
+
+static void highbank_machine_init(void)
+{
+ qemu_register_machine(&highbank_machine);
+}
+
+machine_init(highbank_machine_init);
diff --git a/hw/hpet.c b/hw/hpet.c
index 5312df7c3a..b6ace4e696 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -695,23 +695,34 @@ static int hpet_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo hpet_device_info = {
- .qdev.name = "hpet",
- .qdev.size = sizeof(HPETState),
- .qdev.no_user = 1,
- .qdev.vmsd = &vmstate_hpet,
- .qdev.reset = hpet_reset,
- .init = hpet_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
- DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property hpet_device_properties[] = {
+ DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
+ DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void hpet_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = hpet_init;
+ dc->no_user = 1;
+ dc->reset = hpet_reset;
+ dc->vmsd = &vmstate_hpet;
+ dc->props = hpet_device_properties;
+}
+
+static TypeInfo hpet_device_info = {
+ .name = "hpet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(HPETState),
+ .class_init = hpet_device_class_init,
};
static void hpet_register_device(void)
{
- sysbus_register_withprop(&hpet_device_info);
+ type_register_static(&hpet_device_info);
}
device_init(hpet_register_device)
diff --git a/hw/i2c.c b/hw/i2c.c
index 9bcf3e1d31..8ae4aaae1d 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -12,8 +12,8 @@
struct i2c_bus
{
BusState qbus;
- i2c_slave *current_dev;
- i2c_slave *dev;
+ I2CSlave *current_dev;
+ I2CSlave *dev;
uint8_t saved_address;
};
@@ -21,7 +21,7 @@ static struct BusInfo i2c_bus_info = {
.name = "I2C",
.size = sizeof(i2c_bus),
.props = (Property[]) {
- DEFINE_PROP_UINT8("address", struct i2c_slave, address, 0),
+ DEFINE_PROP_UINT8("address", struct I2CSlave, address, 0),
DEFINE_PROP_END_OF_LIST(),
}
};
@@ -66,7 +66,7 @@ i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
return bus;
}
-void i2c_set_slave_address(i2c_slave *dev, uint8_t address)
+void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
{
dev->address = address;
}
@@ -82,71 +82,100 @@ int i2c_bus_busy(i2c_bus *bus)
int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
{
DeviceState *qdev;
- i2c_slave *slave = NULL;
+ I2CSlave *slave = NULL;
+ I2CSlaveClass *sc;
QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
- i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
+ I2CSlave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
if (candidate->address == address) {
slave = candidate;
break;
}
}
- if (!slave)
+ if (!slave) {
return 1;
+ }
+ sc = I2C_SLAVE_GET_CLASS(slave);
/* If the bus is already busy, assume this is a repeated
start condition. */
bus->current_dev = slave;
- slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+ if (sc->event) {
+ sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+ }
return 0;
}
void i2c_end_transfer(i2c_bus *bus)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return;
+ }
- dev->info->event(dev, I2C_FINISH);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->event) {
+ sc->event(dev, I2C_FINISH);
+ }
bus->current_dev = NULL;
}
int i2c_send(i2c_bus *bus, uint8_t data)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return -1;
+ }
+
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->send) {
+ return sc->send(dev, data);
+ }
- return dev->info->send(dev, data);
+ return -1;
}
int i2c_recv(i2c_bus *bus)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return -1;
+ }
+
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->recv) {
+ return sc->recv(dev);
+ }
- return dev->info->recv(dev);
+ return -1;
}
void i2c_nack(i2c_bus *bus)
{
- i2c_slave *dev = bus->current_dev;
+ I2CSlave *dev = bus->current_dev;
+ I2CSlaveClass *sc;
- if (!dev)
+ if (!dev) {
return;
+ }
- dev->info->event(dev, I2C_NACK);
+ sc = I2C_SLAVE_GET_CLASS(dev);
+ if (sc->event) {
+ sc->event(dev, I2C_NACK);
+ }
}
static int i2c_slave_post_load(void *opaque, int version_id)
{
- i2c_slave *dev = opaque;
+ I2CSlave *dev = opaque;
i2c_bus *bus;
bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
if (bus->saved_address == dev->address) {
@@ -156,33 +185,23 @@ static int i2c_slave_post_load(void *opaque, int version_id)
}
const VMStateDescription vmstate_i2c_slave = {
- .name = "i2c_slave",
+ .name = "I2CSlave",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.post_load = i2c_slave_post_load,
.fields = (VMStateField []) {
- VMSTATE_UINT8(address, i2c_slave),
+ VMSTATE_UINT8(address, I2CSlave),
VMSTATE_END_OF_LIST()
}
};
-static int i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
+static int i2c_slave_qdev_init(DeviceState *dev)
{
- I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
- i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev);
-
- s->info = info;
+ I2CSlave *s = I2C_SLAVE_FROM_QDEV(dev);
+ I2CSlaveClass *sc = I2C_SLAVE_GET_CLASS(s);
- return info->init(s);
-}
-
-void i2c_register_slave(I2CSlaveInfo *info)
-{
- assert(info->qdev.size >= sizeof(i2c_slave));
- info->qdev.init = i2c_slave_qdev_init;
- info->qdev.bus_info = &i2c_bus_info;
- qdev_register(&info->qdev);
+ return sc->init(s);
}
DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
@@ -194,3 +213,26 @@ DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr)
qdev_init_nofail(dev);
return dev;
}
+
+static void i2c_slave_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = i2c_slave_qdev_init;
+ k->bus_info = &i2c_bus_info;
+}
+
+static TypeInfo i2c_slave_type_info = {
+ .name = TYPE_I2C_SLAVE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(I2CSlave),
+ .abstract = true,
+ .class_size = sizeof(I2CSlaveClass),
+ .class_init = i2c_slave_class_init,
+};
+
+static void i2c_slave_register_devices(void)
+{
+ type_register_static(&i2c_slave_type_info);
+}
+
+device_init(i2c_slave_register_devices);
diff --git a/hw/i2c.h b/hw/i2c.h
index a3383ff025..0f5682b4b0 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -15,36 +15,43 @@ enum i2c_event {
I2C_NACK /* Masker NACKed a receive byte. */
};
-/* Master to slave. */
-typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data);
-/* Slave to master. */
-typedef int (*i2c_recv_cb)(i2c_slave *s);
-/* Notify the slave of a bus state change. */
-typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event);
+typedef struct I2CSlave I2CSlave;
-typedef int (*i2c_slave_initfn)(i2c_slave *dev);
+#define TYPE_I2C_SLAVE "i2c-slave"
+#define I2C_SLAVE(obj) \
+ OBJECT_CHECK(I2CSlave, (obj), TYPE_I2C_SLAVE)
+#define I2C_SLAVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(I2CSlaveClass, (klass), TYPE_I2C_SLAVE)
+#define I2C_SLAVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(I2CSlaveClass, (obj), TYPE_I2C_SLAVE)
-typedef struct {
- DeviceInfo qdev;
+typedef struct I2CSlaveClass
+{
+ DeviceClass parent_class;
/* Callbacks provided by the device. */
- i2c_slave_initfn init;
- i2c_event_cb event;
- i2c_recv_cb recv;
- i2c_send_cb send;
-} I2CSlaveInfo;
+ int (*init)(I2CSlave *dev);
+
+ /* Master to slave. */
+ int (*send)(I2CSlave *s, uint8_t data);
+
+ /* Slave to master. */
+ int (*recv)(I2CSlave *s);
-struct i2c_slave
+ /* Notify the slave of a bus state change. */
+ void (*event)(I2CSlave *s, enum i2c_event event);
+} I2CSlaveClass;
+
+struct I2CSlave
{
DeviceState qdev;
- I2CSlaveInfo *info;
/* Remaining fields for internal use by the I2C code. */
uint8_t address;
};
i2c_bus *i2c_init_bus(DeviceState *parent, const char *name);
-void i2c_set_slave_address(i2c_slave *dev, uint8_t address);
+void i2c_set_slave_address(I2CSlave *dev, uint8_t address);
int i2c_bus_busy(i2c_bus *bus);
int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv);
void i2c_end_transfer(i2c_bus *bus);
@@ -52,11 +59,9 @@ void i2c_nack(i2c_bus *bus);
int i2c_send(i2c_bus *bus, uint8_t data);
int i2c_recv(i2c_bus *bus);
-#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(i2c_slave, qdev, dev)
+#define I2C_SLAVE_FROM_QDEV(dev) DO_UPCAST(I2CSlave, qdev, dev)
#define FROM_I2C_SLAVE(type, dev) DO_UPCAST(type, i2c, dev)
-void i2c_register_slave(I2CSlaveInfo *type);
-
DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr);
/* wm8750.c */
@@ -69,7 +74,7 @@ void wm8750_dac_commit(void *opaque);
void wm8750_set_bclk_in(void *opaque, int new_hz);
/* tmp105.c */
-void tmp105_set(i2c_slave *i2c, int temp);
+void tmp105_set(I2CSlave *i2c, int temp);
/* lm832x.c */
void lm832x_key_event(DeviceState *dev, int key, int state);
@@ -78,10 +83,10 @@ extern const VMStateDescription vmstate_i2c_slave;
#define VMSTATE_I2C_SLAVE(_field, _state) { \
.name = (stringify(_field)), \
- .size = sizeof(i2c_slave), \
+ .size = sizeof(I2CSlave), \
.vmsd = &vmstate_i2c_slave, \
.flags = VMS_STRUCT, \
- .offset = vmstate_offset_value(_state, _field, i2c_slave), \
+ .offset = vmstate_offset_value(_state, _field, I2CSlave), \
}
#endif
diff --git a/hw/i82374.c b/hw/i82374.c
new file mode 100644
index 0000000000..220e8cccb6
--- /dev/null
+++ b/hw/i82374.c
@@ -0,0 +1,165 @@
+/*
+ * QEMU Intel 82374 emulation (Enhanced DMA controller)
+ *
+ * Copyright (c) 2010 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "isa.h"
+
+//#define DEBUG_I82374
+
+#ifdef DEBUG_I82374
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82374: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82374 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+typedef struct I82374State {
+ uint8_t commands[8];
+} I82374State;
+
+static const VMStateDescription vmstate_i82374 = {
+ .name = "i82374",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8_ARRAY(commands, I82374State, 8),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static uint32_t i82374_read_isr(void *opaque, uint32_t nport)
+{
+ uint32_t val = 0;
+
+ BADF("%s: %08x\n", __func__, nport);
+
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+ return val;
+}
+
+static void i82374_write_command(void *opaque, uint32_t nport, uint32_t data)
+{
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+ if (data != 0x42) {
+ /* Not Stop S/G command */
+ BADF("%s: %08x=%08x\n", __func__, nport, data);
+ }
+}
+
+static uint32_t i82374_read_status(void *opaque, uint32_t nport)
+{
+ uint32_t val = 0;
+
+ BADF("%s: %08x\n", __func__, nport);
+
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+ return val;
+}
+
+static void i82374_write_descriptor(void *opaque, uint32_t nport, uint32_t data)
+{
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, data);
+
+ BADF("%s: %08x=%08x\n", __func__, nport, data);
+}
+
+static uint32_t i82374_read_descriptor(void *opaque, uint32_t nport)
+{
+ uint32_t val = 0;
+
+ BADF("%s: %08x\n", __func__, nport);
+
+ DPRINTF("%s: %08x=%08x\n", __func__, nport, val);
+ return val;
+}
+
+static void i82374_init(I82374State *s)
+{
+ DMA_init(1, NULL);
+ memset(s->commands, 0, sizeof(s->commands));
+}
+
+typedef struct ISAi82374State {
+ ISADevice dev;
+ uint32_t iobase;
+ I82374State state;
+} ISAi82374State;
+
+static const VMStateDescription vmstate_isa_i82374 = {
+ .name = "isa-i82374",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(state, ISAi82374State, 0, vmstate_i82374, I82374State),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static int i82374_isa_init(ISADevice *dev)
+{
+ ISAi82374State *isa = DO_UPCAST(ISAi82374State, dev, dev);
+ I82374State *s = &isa->state;
+
+ register_ioport_read(isa->iobase + 0x0A, 1, 1, i82374_read_isr, s);
+ register_ioport_write(isa->iobase + 0x10, 8, 1, i82374_write_command, s);
+ register_ioport_read(isa->iobase + 0x18, 8, 1, i82374_read_status, s);
+ register_ioport_write(isa->iobase + 0x20, 0x20, 1, i82374_write_descriptor, s);
+ register_ioport_read(isa->iobase + 0x20, 0x20, 1, i82374_read_descriptor, s);
+
+ i82374_init(s);
+
+ return 0;
+}
+
+static Property i82374_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISAi82374State, iobase, 0x400),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void i82374_class_init(ObjectClass *klass, void *data)
+{
+ ISADeviceClass *k = ISA_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = i82374_isa_init;
+ dc->vmsd = &vmstate_isa_i82374;
+ dc->props = i82374_properties;
+}
+
+static TypeInfo i82374_isa_info = {
+ .name = "i82374",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAi82374State),
+ .class_init = i82374_class_init,
+};
+
+static void i82374_register_devices(void)
+{
+ type_register_static(&i82374_isa_info);
+}
+
+device_init(i82374_register_devices)
diff --git a/hw/i82378.c b/hw/i82378.c
new file mode 100644
index 0000000000..9c3efe8b95
--- /dev/null
+++ b/hw/i82378.c
@@ -0,0 +1,275 @@
+/*
+ * QEMU Intel i82378 emulation (PCI to ISA bridge)
+ *
+ * Copyright (c) 2010-2011 Hervé Poussineau
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "pci.h"
+#include "pc.h"
+
+//#define DEBUG_I82378
+
+#ifdef DEBUG_I82378
+#define DPRINTF(fmt, ...) \
+do { fprintf(stderr, "i82378: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) \
+do {} while (0)
+#endif
+
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "i82378 ERROR: " fmt , ## __VA_ARGS__); } while (0)
+
+typedef struct I82378State {
+ qemu_irq out[2];
+ qemu_irq *i8259;
+ MemoryRegion io;
+ MemoryRegion mem;
+} I82378State;
+
+typedef struct PCIi82378State {
+ PCIDevice pci_dev;
+ uint32_t isa_io_base;
+ uint32_t isa_mem_base;
+ I82378State state;
+} PCIi82378State;
+
+static const VMStateDescription vmstate_pci_i82378 = {
+ .name = "pci-i82378",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(pci_dev, PCIi82378State),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void i82378_io_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned int size)
+{
+ switch (size) {
+ case 1:
+ DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outb(addr, value);
+ break;
+ case 2:
+ DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outw(addr, value);
+ break;
+ case 4:
+ DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outl(addr, value);
+ break;
+ default:
+ abort();
+ }
+}
+
+static uint64_t i82378_io_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+ switch (size) {
+ case 1:
+ return cpu_inb(addr);
+ case 2:
+ return cpu_inw(addr);
+ case 4:
+ return cpu_inl(addr);
+ default:
+ abort();
+ }
+}
+
+static const MemoryRegionOps i82378_io_ops = {
+ .read = i82378_io_read,
+ .write = i82378_io_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void i82378_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned int size)
+{
+ switch (size) {
+ case 1:
+ DPRINTF("%s: " TARGET_FMT_plx "=%02" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outb(addr, value);
+ break;
+ case 2:
+ DPRINTF("%s: " TARGET_FMT_plx "=%04" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outw(addr, value);
+ break;
+ case 4:
+ DPRINTF("%s: " TARGET_FMT_plx "=%08" PRIx64 "\n", __func__,
+ addr, value);
+ cpu_outl(addr, value);
+ break;
+ default:
+ abort();
+ }
+}
+
+static uint64_t i82378_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
+{
+ DPRINTF("%s: " TARGET_FMT_plx "\n", __func__, addr);
+ switch (size) {
+ case 1:
+ return cpu_inb(addr);
+ case 2:
+ return cpu_inw(addr);
+ case 4:
+ return cpu_inl(addr);
+ default:
+ abort();
+ }
+}
+
+static const MemoryRegionOps i82378_mem_ops = {
+ .read = i82378_mem_read,
+ .write = i82378_mem_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void i82378_request_out0_irq(void *opaque, int irq, int level)
+{
+ I82378State *s = opaque;
+ qemu_set_irq(s->out[0], level);
+}
+
+static void i82378_request_pic_irq(void *opaque, int irq, int level)
+{
+ DeviceState *dev = opaque;
+ PCIDevice *pci = DO_UPCAST(PCIDevice, qdev, dev);
+ PCIi82378State *s = DO_UPCAST(PCIi82378State, pci_dev, pci);
+
+ qemu_set_irq(s->state.i8259[irq], level);
+}
+
+static void i82378_init(DeviceState *dev, I82378State *s)
+{
+ ISABus *isabus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(dev, "isa.0"));
+ ISADevice *pit;
+ qemu_irq *out0_irq;
+
+ /* This device has:
+ 2 82C59 (irq)
+ 1 82C54 (pit)
+ 2 82C37 (dma)
+ NMI
+ Utility Bus Support Registers
+
+ All devices accept byte access only, except timer
+ */
+
+ qdev_init_gpio_out(dev, s->out, 2);
+ qdev_init_gpio_in(dev, i82378_request_pic_irq, 16);
+
+ /* Workaround the fact that i8259 is not qdev'ified... */
+ out0_irq = qemu_allocate_irqs(i82378_request_out0_irq, s, 1);
+
+ /* 2 82C59 (irq) */
+ s->i8259 = i8259_init(isabus, *out0_irq);
+ isa_bus_irqs(isabus, s->i8259);
+
+ /* 1 82C54 (pit) */
+ pit = pit_init(isabus, 0x40, 0);
+
+ /* speaker */
+ pcspk_init(pit);
+
+ /* 2 82C37 (dma) */
+ DMA_init(1, &s->out[1]);
+ isa_create_simple(isabus, "i82374");
+
+ /* timer */
+ isa_create_simple(isabus, "mc146818rtc");
+}
+
+static int pci_i82378_init(PCIDevice *dev)
+{
+ PCIi82378State *pci = DO_UPCAST(PCIi82378State, pci_dev, dev);
+ I82378State *s = &pci->state;
+ uint8_t *pci_conf;
+
+ pci_conf = dev->config;
+ pci_set_word(pci_conf + PCI_COMMAND,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_set_word(pci_conf + PCI_STATUS,
+ PCI_STATUS_DEVSEL_MEDIUM);
+
+ pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
+
+ memory_region_init_io(&s->io, &i82378_io_ops, s, "i82378-io", 0x00010000);
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->io);
+
+ memory_region_init_io(&s->mem, &i82378_mem_ops, s, "i82378-mem", 0x01000000);
+ memory_region_set_coalescing(&s->mem);
+ pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+
+ /* Make I/O address read only */
+ pci_set_word(dev->wmask + PCI_COMMAND, PCI_COMMAND_SPECIAL);
+ pci_set_long(dev->wmask + PCI_BASE_ADDRESS_0, 0);
+ pci_set_long(pci_conf + PCI_BASE_ADDRESS_0, pci->isa_io_base);
+
+ isa_mem_base = pci->isa_mem_base;
+ isa_bus_new(&dev->qdev, pci_address_space_io(dev));
+
+ i82378_init(&dev->qdev, s);
+
+ return 0;
+}
+
+static Property i82378_properties[] = {
+ DEFINE_PROP_HEX32("iobase", PCIi82378State, isa_io_base, 0x80000000),
+ DEFINE_PROP_HEX32("membase", PCIi82378State, isa_mem_base, 0xc0000000),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void pci_i82378_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = pci_i82378_init;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82378;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+ k->subsystem_vendor_id = 0x0;
+ k->subsystem_id = 0x0;
+ dc->vmsd = &vmstate_pci_i82378;
+ dc->props = i82378_properties;
+}
+
+static TypeInfo pci_i82378_info = {
+ .name = "i82378",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIi82378State),
+ .class_init = pci_i82378_class_init,
+};
+
+static void i82378_register_devices(void)
+{
+ type_register_static(&pci_i82378_info);
+}
+
+device_init(i82378_register_devices)
diff --git a/hw/i8254.c b/hw/i8254.c
index cf9ed2ff25..522fed8809 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -535,22 +535,32 @@ static int pit_initfn(ISADevice *dev)
return 0;
}
-static ISADeviceInfo pit_info = {
- .qdev.name = "isa-pit",
- .qdev.size = sizeof(PITState),
- .qdev.vmsd = &vmstate_pit,
- .qdev.reset = pit_reset,
- .qdev.no_user = 1,
- .init = pit_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("irq", PITState, irq, -1),
- DEFINE_PROP_HEX32("iobase", PITState, iobase, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pit_properties[] = {
+ DEFINE_PROP_UINT32("irq", PITState, irq, -1),
+ DEFINE_PROP_HEX32("iobase", PITState, iobase, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pit_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = pit_initfn;
+ dc->no_user = 1;
+ dc->reset = pit_reset;
+ dc->vmsd = &vmstate_pit;
+ dc->props = pit_properties;
+}
+
+static TypeInfo pit_info = {
+ .name = "isa-pit",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(PITState),
+ .class_init = pit_class_initfn,
};
static void pit_register(void)
{
- isa_qdev_register(&pit_info);
+ type_register_static(&pit_info);
}
device_init(pit_register)
diff --git a/hw/i8259.c b/hw/i8259.c
index 7331e0e61c..7ae53805d7 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -26,6 +26,7 @@
#include "isa.h"
#include "monitor.h"
#include "qemu-timer.h"
+#include "i8259_internal.h"
/* debug PIC */
//#define DEBUG_PIC
@@ -40,33 +41,6 @@
//#define DEBUG_IRQ_LATENCY
//#define DEBUG_IRQ_COUNT
-struct PicState {
- ISADevice dev;
- uint8_t last_irr; /* edge detection */
- uint8_t irr; /* interrupt request register */
- uint8_t imr; /* interrupt mask register */
- uint8_t isr; /* interrupt service register */
- uint8_t priority_add; /* highest irq priority */
- uint8_t irq_base;
- uint8_t read_reg_select;
- uint8_t poll;
- uint8_t special_mask;
- uint8_t init_state;
- uint8_t auto_eoi;
- uint8_t rotate_on_auto_eoi;
- uint8_t special_fully_nested_mode;
- uint8_t init4; /* true if 4 byte init */
- uint8_t single_mode; /* true if slave pic is not initialized */
- uint8_t elcr; /* PIIX edge/trigger selection*/
- uint8_t elcr_mask;
- qemu_irq int_out[1];
- uint32_t master; /* reflects /SP input pin */
- uint32_t iobase;
- uint32_t elcr_addr;
- MemoryRegion base_io;
- MemoryRegion elcr_io;
-};
-
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
static int irq_level[16];
#endif
@@ -76,12 +50,12 @@ static uint64_t irq_count[16];
#ifdef DEBUG_IRQ_LATENCY
static int64_t irq_time[16];
#endif
-PicState *isa_pic;
-static PicState *slave_pic;
+DeviceState *isa_pic;
+static PICCommonState *slave_pic;
/* return the highest priority found in mask (highest = smallest
number). Return 8 if no irq */
-static int get_priority(PicState *s, int mask)
+static int get_priority(PICCommonState *s, int mask)
{
int priority;
@@ -96,7 +70,7 @@ static int get_priority(PicState *s, int mask)
}
/* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PicState *s)
+static int pic_get_irq(PICCommonState *s)
{
int mask, cur_priority, priority;
@@ -125,7 +99,7 @@ static int pic_get_irq(PicState *s)
}
/* Update INT output. Must be called every time the output may have changed. */
-static void pic_update_irq(PicState *s)
+static void pic_update_irq(PICCommonState *s)
{
int irq;
@@ -142,7 +116,7 @@ static void pic_update_irq(PicState *s)
/* set irq level. If an edge is detected, then the IRR is set to 1 */
static void pic_set_irq(void *opaque, int irq, int level)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
int mask = 1 << irq;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
@@ -190,7 +164,7 @@ static void pic_set_irq(void *opaque, int irq, int level)
}
/* acknowledge interrupt 'irq' */
-static void pic_intack(PicState *s, int irq)
+static void pic_intack(PICCommonState *s, int irq)
{
if (s->auto_eoi) {
if (s->rotate_on_auto_eoi) {
@@ -206,8 +180,9 @@ static void pic_intack(PicState *s, int irq)
pic_update_irq(s);
}
-int pic_read_irq(PicState *s)
+int pic_read_irq(DeviceState *d)
{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
int irq, irq2, intno;
irq = pic_get_irq(s);
@@ -246,30 +221,15 @@ int pic_read_irq(PicState *s)
return intno;
}
-static void pic_init_reset(PicState *s)
+static void pic_init_reset(PICCommonState *s)
{
- s->last_irr = 0;
- s->irr = 0;
- s->imr = 0;
- s->isr = 0;
- s->priority_add = 0;
- s->irq_base = 0;
- s->read_reg_select = 0;
- s->poll = 0;
- s->special_mask = 0;
- s->init_state = 0;
- s->auto_eoi = 0;
- s->rotate_on_auto_eoi = 0;
- s->special_fully_nested_mode = 0;
- s->init4 = 0;
- s->single_mode = 0;
- /* Note: ELCR is not reset */
+ pic_reset_common(s);
pic_update_irq(s);
}
static void pic_reset(DeviceState *dev)
{
- PicState *s = container_of(dev, PicState, dev.qdev);
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
pic_init_reset(s);
s->elcr = 0;
@@ -278,7 +238,7 @@ static void pic_reset(DeviceState *dev)
static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
uint64_t val64, unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
uint32_t addr = addr64;
uint32_t val = val64;
int priority, cmd, irq;
@@ -372,7 +332,7 @@ static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
int ret;
if (s->poll) {
@@ -399,51 +359,27 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
return ret;
}
-int pic_get_output(PicState *s)
+int pic_get_output(DeviceState *d)
{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
+
return (pic_get_irq(s) >= 0);
}
static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
uint64_t val, unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
s->elcr = val & s->elcr_mask;
}
static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
unsigned size)
{
- PicState *s = opaque;
+ PICCommonState *s = opaque;
return s->elcr;
}
-static const VMStateDescription vmstate_pic = {
- .name = "i8259",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(last_irr, PicState),
- VMSTATE_UINT8(irr, PicState),
- VMSTATE_UINT8(imr, PicState),
- VMSTATE_UINT8(isr, PicState),
- VMSTATE_UINT8(priority_add, PicState),
- VMSTATE_UINT8(irq_base, PicState),
- VMSTATE_UINT8(read_reg_select, PicState),
- VMSTATE_UINT8(poll, PicState),
- VMSTATE_UINT8(special_mask, PicState),
- VMSTATE_UINT8(init_state, PicState),
- VMSTATE_UINT8(auto_eoi, PicState),
- VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
- VMSTATE_UINT8(special_fully_nested_mode, PicState),
- VMSTATE_UINT8(init4, PicState),
- VMSTATE_UINT8(single_mode, PicState),
- VMSTATE_UINT8(elcr, PicState),
- VMSTATE_END_OF_LIST()
- }
-};
-
static const MemoryRegionOps pic_base_ioport_ops = {
.read = pic_ioport_read,
.write = pic_ioport_write,
@@ -462,36 +398,25 @@ static const MemoryRegionOps pic_elcr_ioport_ops = {
},
};
-static int pic_initfn(ISADevice *dev)
+static void pic_init(PICCommonState *s)
{
- PicState *s = DO_UPCAST(PicState, dev, dev);
-
memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
- isa_register_ioport(dev, &s->base_io, s->iobase);
- if (s->elcr_addr != -1) {
- isa_register_ioport(dev, &s->elcr_io, s->elcr_addr);
- }
-
- qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
- qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
-
- qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
-
- return 0;
+ qdev_init_gpio_out(&s->dev.qdev, s->int_out, ARRAY_SIZE(s->int_out));
+ qdev_init_gpio_in(&s->dev.qdev, pic_set_irq, 8);
}
void pic_info(Monitor *mon)
{
int i;
- PicState *s;
+ PICCommonState *s;
if (!isa_pic) {
return;
}
for (i = 0; i < 2; i++) {
- s = i == 0 ? isa_pic : slave_pic;
+ s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic;
monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
"irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
i, s->irr, s->imr, s->isr, s->priority_add,
@@ -526,54 +451,46 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
- dev = isa_create(bus, "isa-i8259");
- qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
- qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
- qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
- qdev_prop_set_bit(&dev->qdev, "master", true);
- qdev_init_nofail(&dev->qdev);
+ dev = i8259_init_chip("isa-i8259", bus, true);
qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
for (i = 0 ; i < 8; i++) {
irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
}
- isa_pic = DO_UPCAST(PicState, dev, dev);
+ isa_pic = &dev->qdev;
- dev = isa_create(bus, "isa-i8259");
- qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
- qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
- qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
- qdev_init_nofail(&dev->qdev);
+ dev = i8259_init_chip("isa-i8259", bus, false);
qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
for (i = 0 ; i < 8; i++) {
irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
}
- slave_pic = DO_UPCAST(PicState, dev, dev);
+ slave_pic = DO_UPCAST(PICCommonState, dev, dev);
return irq_set;
}
-static ISADeviceInfo i8259_info = {
- .qdev.name = "isa-i8259",
- .qdev.size = sizeof(PicState),
- .qdev.vmsd = &vmstate_pic,
- .qdev.reset = pic_reset,
- .qdev.no_user = 1,
- .init = pic_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", PicState, iobase, -1),
- DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr, -1),
- DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask, -1),
- DEFINE_PROP_BIT("master", PicState, master, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void i8259_class_init(ObjectClass *klass, void *data)
+{
+ PICCommonClass *k = PIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = pic_init;
+ dc->reset = pic_reset;
+}
+
+static TypeInfo i8259_info = {
+ .name = "isa-i8259",
+ .instance_size = sizeof(PICCommonState),
+ .parent = TYPE_PIC_COMMON,
+ .class_init = i8259_class_init,
};
static void pic_register(void)
{
- isa_qdev_register(&i8259_info);
+ type_register_static(&i8259_info);
}
+
device_init(pic_register)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
new file mode 100644
index 0000000000..9f150bc6d0
--- /dev/null
+++ b/hw/i8259_common.c
@@ -0,0 +1,161 @@
+/*
+ * QEMU 8259 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "pc.h"
+#include "i8259_internal.h"
+
+void pic_reset_common(PICCommonState *s)
+{
+ s->last_irr = 0;
+ s->irr = 0;
+ s->imr = 0;
+ s->isr = 0;
+ s->priority_add = 0;
+ s->irq_base = 0;
+ s->read_reg_select = 0;
+ s->poll = 0;
+ s->special_mask = 0;
+ s->init_state = 0;
+ s->auto_eoi = 0;
+ s->rotate_on_auto_eoi = 0;
+ s->special_fully_nested_mode = 0;
+ s->init4 = 0;
+ s->single_mode = 0;
+ /* Note: ELCR is not reset */
+}
+
+static void pic_dispatch_pre_save(void *opaque)
+{
+ PICCommonState *s = opaque;
+ PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+ if (info->pre_save) {
+ info->pre_save(s);
+ }
+}
+
+static int pic_dispatch_post_load(void *opaque, int version_id)
+{
+ PICCommonState *s = opaque;
+ PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+ if (info->post_load) {
+ info->post_load(s);
+ }
+ return 0;
+}
+
+static int pic_init_common(ISADevice *dev)
+{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev, dev);
+ PICCommonClass *info = PIC_COMMON_GET_CLASS(s);
+
+ info->init(s);
+
+ isa_register_ioport(NULL, &s->base_io, s->iobase);
+ if (s->elcr_addr != -1) {
+ isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
+ }
+
+ qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
+
+ return 0;
+}
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
+{
+ ISADevice *dev;
+
+ dev = isa_create(bus, name);
+ qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
+ qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
+ qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
+ qdev_prop_set_bit(&dev->qdev, "master", master);
+ qdev_init_nofail(&dev->qdev);
+
+ return dev;
+}
+
+static const VMStateDescription vmstate_pic_common = {
+ .name = "i8259",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = pic_dispatch_pre_save,
+ .post_load = pic_dispatch_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(last_irr, PICCommonState),
+ VMSTATE_UINT8(irr, PICCommonState),
+ VMSTATE_UINT8(imr, PICCommonState),
+ VMSTATE_UINT8(isr, PICCommonState),
+ VMSTATE_UINT8(priority_add, PICCommonState),
+ VMSTATE_UINT8(irq_base, PICCommonState),
+ VMSTATE_UINT8(read_reg_select, PICCommonState),
+ VMSTATE_UINT8(poll, PICCommonState),
+ VMSTATE_UINT8(special_mask, PICCommonState),
+ VMSTATE_UINT8(init_state, PICCommonState),
+ VMSTATE_UINT8(auto_eoi, PICCommonState),
+ VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
+ VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
+ VMSTATE_UINT8(init4, PICCommonState),
+ VMSTATE_UINT8(single_mode, PICCommonState),
+ VMSTATE_UINT8(elcr, PICCommonState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property pic_properties_common[] = {
+ DEFINE_PROP_HEX32("iobase", PICCommonState, iobase, -1),
+ DEFINE_PROP_HEX32("elcr_addr", PICCommonState, elcr_addr, -1),
+ DEFINE_PROP_HEX8("elcr_mask", PICCommonState, elcr_mask, -1),
+ DEFINE_PROP_BIT("master", PICCommonState, master, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pic_common_class_init(ObjectClass *klass, void *data)
+{
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_pic_common;
+ dc->no_user = 1;
+ dc->props = pic_properties_common;
+ ic->init = pic_init_common;
+}
+
+static TypeInfo pic_common_type = {
+ .name = TYPE_PIC_COMMON,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(PICCommonState),
+ .class_size = sizeof(PICCommonClass),
+ .class_init = pic_common_class_init,
+ .abstract = true,
+};
+
+static void register_devices(void)
+{
+ type_register_static(&pic_common_type);
+}
+
+device_init(register_devices);
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
new file mode 100644
index 0000000000..4137b61703
--- /dev/null
+++ b/hw/i8259_internal.h
@@ -0,0 +1,82 @@
+/*
+ * QEMU 8259 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8259_INTERNAL_H
+#define QEMU_I8259_INTERNAL_H
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+
+typedef struct PICCommonState PICCommonState;
+
+#define TYPE_PIC_COMMON "pic-common"
+#define PIC_COMMON(obj) \
+ OBJECT_CHECK(PICCommon, (obj), TYPE_PIC_COMMON)
+#define PIC_COMMON_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PICCommonClass, (klass), TYPE_PIC_COMMON)
+#define PIC_COMMON_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PICCommonClass, (obj), TYPE_PIC_COMMON)
+
+typedef struct PICCommonClass
+{
+ ISADeviceClass parent_class;
+ void (*init)(PICCommonState *s);
+ void (*pre_save)(PICCommonState *s);
+ void (*post_load)(PICCommonState *s);
+} PICCommonClass;
+
+struct PICCommonState {
+ ISADevice dev;
+ uint8_t last_irr; /* edge detection */
+ uint8_t irr; /* interrupt request register */
+ uint8_t imr; /* interrupt mask register */
+ uint8_t isr; /* interrupt service register */
+ uint8_t priority_add; /* highest irq priority */
+ uint8_t irq_base;
+ uint8_t read_reg_select;
+ uint8_t poll;
+ uint8_t special_mask;
+ uint8_t init_state;
+ uint8_t auto_eoi;
+ uint8_t rotate_on_auto_eoi;
+ uint8_t special_fully_nested_mode;
+ uint8_t init4; /* true if 4 byte init */
+ uint8_t single_mode; /* true if slave pic is not initialized */
+ uint8_t elcr; /* PIIX edge/trigger selection*/
+ uint8_t elcr_mask;
+ qemu_irq int_out[1];
+ uint32_t master; /* reflects /SP input pin */
+ uint32_t iobase;
+ uint32_t elcr_addr;
+ MemoryRegion base_io;
+ MemoryRegion elcr_io;
+};
+
+void pic_reset_common(PICCommonState *s);
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
+
+
+#endif /* !QEMU_I8259_INTERNAL_H */
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 0af201de2f..c87a6ca515 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -25,6 +25,7 @@
#include <hw/msi.h>
#include <hw/pc.h>
#include <hw/pci.h>
+#include <hw/sysbus.h>
#include "monitor.h"
#include "dma.h"
@@ -1214,3 +1215,55 @@ void ahci_reset(void *opaque)
ahci_reset_port(&d->ahci, i);
}
}
+
+typedef struct SysbusAHCIState {
+ SysBusDevice busdev;
+ AHCIState ahci;
+ uint32_t num_ports;
+} SysbusAHCIState;
+
+static const VMStateDescription vmstate_sysbus_ahci = {
+ .name = "sysbus-ahci",
+ .unmigratable = 1,
+};
+
+static int sysbus_ahci_init(SysBusDevice *dev)
+{
+ SysbusAHCIState *s = FROM_SYSBUS(SysbusAHCIState, dev);
+ ahci_init(&s->ahci, &dev->qdev, s->num_ports);
+
+ sysbus_init_mmio(dev, &s->ahci.mem);
+ sysbus_init_irq(dev, &s->ahci.irq);
+
+ qemu_register_reset(ahci_reset, &s->ahci);
+ return 0;
+}
+
+static Property sysbus_ahci_properties[] = {
+ DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, num_ports, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sysbus_ahci_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sbc->init = sysbus_ahci_init;
+ dc->vmsd = &vmstate_sysbus_ahci;
+ dc->props = sysbus_ahci_properties;
+}
+
+static TypeInfo sysbus_ahci_info = {
+ .name = "sysbus-ahci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysbusAHCIState),
+ .class_init = sysbus_ahci_class_init,
+};
+
+static void sysbus_ahci_register(void)
+{
+ type_register_static(&sysbus_ahci_info);
+}
+
+device_init(sysbus_ahci_register);
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 5fe98b1bb3..a119500f40 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -325,27 +325,34 @@ void pci_cmd646_ide_init(PCIBus *bus, DriveInfo **hd_table,
pci_ide_create_devs(dev, hd_table);
}
-static PCIDeviceInfo cmd646_ide_info[] = {
- {
- .qdev.name = "cmd646-ide",
- .qdev.size = sizeof(PCIIDEState),
- .init = pci_cmd646_ide_initfn,
- .exit = pci_cmd646_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_CMD,
- .device_id = PCI_DEVICE_ID_CMD_646,
- .revision = 0x07, // IDE controller revision
- .class_id = PCI_CLASS_STORAGE_IDE,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
- },{
- /* end of list */
- }
+static Property cmd646_ide_properties[] = {
+ DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void cmd646_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_cmd646_ide_initfn;
+ k->exit = pci_cmd646_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_CMD;
+ k->device_id = PCI_DEVICE_ID_CMD_646;
+ k->revision = 0x07;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->props = cmd646_ide_properties;
+}
+
+static TypeInfo cmd646_ide_info = {
+ .name = "cmd646-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = cmd646_ide_class_init,
};
static void cmd646_ide_register(void)
{
- pci_qdev_register_many(cmd646_ide_info);
+ type_register_static(&cmd646_ide_info);
}
device_init(cmd646_ide_register);
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index 3f7510f52e..5cdaa990ea 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -146,26 +146,30 @@ static void pci_ich9_write_config(PCIDevice *pci, uint32_t addr,
msi_write_config(pci, addr, val, len);
}
-static PCIDeviceInfo ich_ahci_info[] = {
- {
- .qdev.name = "ich9-ahci",
- .qdev.alias = "ahci",
- .qdev.size = sizeof(AHCIPCIState),
- .qdev.vmsd = &vmstate_ahci,
- .init = pci_ich9_ahci_init,
- .exit = pci_ich9_uninit,
- .config_write = pci_ich9_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801IR,
- .revision = 0x02,
- .class_id = PCI_CLASS_STORAGE_SATA,
- },{
- /* end of list */
- }
+static void ich_ahci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ich9_ahci_init;
+ k->exit = pci_ich9_uninit;
+ k->config_write = pci_ich9_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801IR;
+ k->revision = 0x02;
+ k->class_id = PCI_CLASS_STORAGE_SATA;
+ dc->vmsd = &vmstate_ahci;
+}
+
+static TypeInfo ich_ahci_info = {
+ .name = "ich9-ahci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(AHCIPCIState),
+ .class_init = ich_ahci_class_init,
};
static void ich_ahci_register(void)
{
- pci_qdev_register_many(ich_ahci_info);
+ type_register_static(&ich_ahci_info);
}
device_init(ich_ahci_register);
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 00b28dfdbc..c808a0ddf8 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -21,7 +21,6 @@
typedef struct IDEBus IDEBus;
typedef struct IDEDevice IDEDevice;
-typedef struct IDEDeviceInfo IDEDeviceInfo;
typedef struct IDEState IDEState;
typedef struct IDEDMA IDEDMA;
typedef struct IDEDMAOps IDEDMAOps;
@@ -450,6 +449,19 @@ struct IDEBus {
int error_status;
};
+#define TYPE_IDE_DEVICE "ide-device"
+#define IDE_DEVICE(obj) \
+ OBJECT_CHECK(IDEDevice, (obj), TYPE_IDE_DEVICE)
+#define IDE_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(IDEDeviceClass, (klass), TYPE_IDE_DEVICE)
+#define IDE_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(IDEDeviceClass, (obj), TYPE_IDE_DEVICE)
+
+typedef struct IDEDeviceClass {
+ DeviceClass parent_class;
+ int (*init)(IDEDevice *dev);
+} IDEDeviceClass;
+
struct IDEDevice {
DeviceState qdev;
uint32_t unit;
@@ -458,12 +470,6 @@ struct IDEDevice {
char *serial;
};
-typedef int (*ide_qdev_initfn)(IDEDevice *dev);
-struct IDEDeviceInfo {
- DeviceInfo qdev;
- ide_qdev_initfn init;
-};
-
#define BM_STATUS_DMAING 0x01
#define BM_STATUS_ERROR 0x02
#define BM_STATUS_INT 0x04
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index 219f3a4c6b..a0bcb43eba 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -94,23 +94,33 @@ ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
return dev;
}
-static ISADeviceInfo isa_ide_info = {
- .qdev.name = "isa-ide",
- .qdev.fw_name = "ide",
- .qdev.size = sizeof(ISAIDEState),
- .init = isa_ide_initfn,
- .qdev.reset = isa_ide_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", ISAIDEState, iobase, 0x1f0),
- DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
- DEFINE_PROP_UINT32("irq", ISAIDEState, isairq, 14),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property isa_ide_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISAIDEState, iobase, 0x1f0),
+ DEFINE_PROP_HEX32("iobase2", ISAIDEState, iobase2, 0x3f6),
+ DEFINE_PROP_UINT32("irq", ISAIDEState, isairq, 14),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_ide_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = isa_ide_initfn;
+ dc->fw_name = "ide";
+ dc->reset = isa_ide_reset;
+ dc->props = isa_ide_properties;
+}
+
+static TypeInfo isa_ide_info = {
+ .name = "isa-ide",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAIDEState),
+ .class_init = isa_ide_class_initfn,
};
static void isa_ide_register_devices(void)
{
- isa_qdev_register(&isa_ide_info);
+ type_register_static(&isa_ide_info);
}
device_init(isa_ide_register_devices)
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index cb3de6537b..246dd5704b 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -327,7 +327,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val)
bm->cmd = val & 0x09;
}
-static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr,
+static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr,
unsigned width)
{
BMDMAState *bm = opaque;
@@ -341,7 +341,7 @@ static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr,
return data;
}
-static void bmdma_addr_write(void *opaque, dma_addr_t addr,
+static void bmdma_addr_write(void *opaque, target_phys_addr_t addr,
uint64_t data, unsigned width)
{
BMDMAState *bm = opaque;
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index 34733454ea..bf4465bb49 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -195,7 +195,6 @@ PCIDevice *pci_piix3_xen_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
PCIDevice *dev;
dev = pci_create_simple(bus, devfn, "piix3-ide-xen");
- dev->qdev.info->unplug = pci_piix3_xen_ide_unplug;
pci_ide_create_devs(dev, hd_table);
return dev;
}
@@ -238,42 +237,72 @@ PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
return dev;
}
-static PCIDeviceInfo piix_ide_info[] = {
- {
- .qdev.name = "piix3-ide",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = pci_piix_ide_initfn,
- .exit = pci_piix_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
- .class_id = PCI_CLASS_STORAGE_IDE,
- },{
- .qdev.name = "piix3-ide-xen",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .init = pci_piix_ide_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_1,
- .class_id = PCI_CLASS_STORAGE_IDE,
- },{
- .qdev.name = "piix4-ide",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = pci_piix_ide_initfn,
- .exit = pci_piix_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB,
- .class_id = PCI_CLASS_STORAGE_IDE,
- },{
- /* end of list */
- }
+static void piix3_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_piix_ide_initfn;
+ k->exit = pci_piix_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+}
+
+static TypeInfo piix3_ide_info = {
+ .name = "piix3-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = piix3_ide_class_init,
+};
+
+static void piix3_ide_xen_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_piix_ide_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_1;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+ dc->unplug = pci_piix3_xen_ide_unplug;
+}
+
+static TypeInfo piix3_ide_xen_info = {
+ .name = "piix3-ide-xen",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = piix3_ide_xen_class_init,
+};
+
+static void piix4_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_piix_ide_initfn;
+ k->exit = pci_piix_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+}
+
+static TypeInfo piix4_ide_info = {
+ .name = "piix4-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = piix4_ide_class_init,
};
static void piix_ide_register(void)
{
- pci_qdev_register_many(piix_ide_info);
+ type_register_static(&piix3_ide_info);
+ type_register_static(&piix3_ide_xen_info);
+ type_register_static(&piix4_ide_info);
}
device_init(piix_ide_register);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 42071277bb..1640616906 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -53,10 +53,10 @@ static char *idebus_get_fw_dev_path(DeviceState *dev)
return strdup(path);
}
-static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int ide_qdev_init(DeviceState *qdev)
{
- IDEDevice *dev = DO_UPCAST(IDEDevice, qdev, qdev);
- IDEDeviceInfo *info = DO_UPCAST(IDEDeviceInfo, qdev, base);
+ IDEDevice *dev = IDE_DEVICE(qdev);
+ IDEDeviceClass *dc = IDE_DEVICE_GET_CLASS(dev);
IDEBus *bus = DO_UPCAST(IDEBus, qbus, qdev->parent_bus);
if (!dev->conf.bs) {
@@ -85,19 +85,12 @@ static int ide_qdev_init(DeviceState *qdev, DeviceInfo *base)
error_report("Invalid IDE unit %d", dev->unit);
goto err;
}
- return info->init(dev);
+ return dc->init(dev);
err:
return -1;
}
-static void ide_qdev_register(IDEDeviceInfo *info)
-{
- info->qdev.init = ide_qdev_init;
- info->qdev.bus_info = &ide_bus_info;
- qdev_register(&info->qdev);
-}
-
IDEDevice *ide_create_drive(IDEBus *bus, int unit, DriveInfo *drive)
{
DeviceState *dev;
@@ -182,46 +175,93 @@ static int ide_drive_initfn(IDEDevice *dev)
DEFINE_PROP_STRING("ver", IDEDrive, dev.version), \
DEFINE_PROP_STRING("serial", IDEDrive, dev.serial)
-static IDEDeviceInfo ide_dev_info[] = {
- {
- .qdev.name = "ide-hd",
- .qdev.fw_name = "drive",
- .qdev.desc = "virtual IDE disk",
- .qdev.size = sizeof(IDEDrive),
- .init = ide_hd_initfn,
- .qdev.props = (Property[]) {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- }
- },{
- .qdev.name = "ide-cd",
- .qdev.fw_name = "drive",
- .qdev.desc = "virtual IDE CD-ROM",
- .qdev.size = sizeof(IDEDrive),
- .init = ide_cd_initfn,
- .qdev.props = (Property[]) {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- }
- },{
- .qdev.name = "ide-drive", /* legacy -device ide-drive */
- .qdev.fw_name = "drive",
- .qdev.desc = "virtual IDE disk or CD-ROM (legacy)",
- .qdev.size = sizeof(IDEDrive),
- .init = ide_drive_initfn,
- .qdev.props = (Property[]) {
- DEFINE_IDE_DEV_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- }
- }
+static Property ide_hd_properties[] = {
+ DEFINE_IDE_DEV_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
};
-static void ide_dev_register(void)
+static void ide_hd_class_init(ObjectClass *klass, void *data)
{
- int i;
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+ k->init = ide_hd_initfn;
+ dc->fw_name = "drive";
+ dc->desc = "virtual IDE disk";
+ dc->props = ide_hd_properties;
+}
- for (i = 0; i < ARRAY_SIZE(ide_dev_info); i++) {
- ide_qdev_register(&ide_dev_info[i]);
- }
+static TypeInfo ide_hd_info = {
+ .name = "ide-hd",
+ .parent = TYPE_IDE_DEVICE,
+ .instance_size = sizeof(IDEDrive),
+ .class_init = ide_hd_class_init,
+};
+
+static Property ide_cd_properties[] = {
+ DEFINE_IDE_DEV_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_cd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+ k->init = ide_cd_initfn;
+ dc->fw_name = "drive";
+ dc->desc = "virtual IDE CD-ROM";
+ dc->props = ide_cd_properties;
+}
+
+static TypeInfo ide_cd_info = {
+ .name = "ide-cd",
+ .parent = TYPE_IDE_DEVICE,
+ .instance_size = sizeof(IDEDrive),
+ .class_init = ide_cd_class_init,
+};
+
+static Property ide_drive_properties[] = {
+ DEFINE_IDE_DEV_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ide_drive_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IDEDeviceClass *k = IDE_DEVICE_CLASS(klass);
+ k->init = ide_drive_initfn;
+ dc->fw_name = "drive";
+ dc->desc = "virtual IDE disk or CD-ROM (legacy)";
+ dc->props = ide_drive_properties;
+}
+
+static TypeInfo ide_drive_info = {
+ .name = "ide-drive",
+ .parent = TYPE_IDE_DEVICE,
+ .instance_size = sizeof(IDEDrive),
+ .class_init = ide_drive_class_init,
+};
+
+static void ide_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = ide_qdev_init;
+ k->bus_info = &ide_bus_info;
+}
+
+static TypeInfo ide_device_type_info = {
+ .name = TYPE_IDE_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(IDEDevice),
+ .abstract = true,
+ .class_size = sizeof(IDEDeviceClass),
+ .class_init = ide_device_class_init,
+};
+
+static void ide_dev_register(void)
+{
+ type_register_static(&ide_hd_info);
+ type_register_static(&ide_cd_info);
+ type_register_static(&ide_drive_info);
+ type_register_static(&ide_device_type_info);
}
device_init(ide_dev_register);
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 4ea2064498..b4ca6f27b3 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -213,20 +213,29 @@ void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn)
pci_ide_create_devs(dev, hd_table);
}
-static PCIDeviceInfo via_ide_info = {
- .qdev.name = "via-ide",
- .qdev.size = sizeof(PCIIDEState),
- .qdev.no_user = 1,
- .init = vt82c686b_ide_initfn,
- .exit = vt82c686b_ide_exitfn,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_IDE,
- .revision = 0x06,
- .class_id = PCI_CLASS_STORAGE_IDE,
+static void via_ide_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_ide_initfn;
+ k->exit = vt82c686b_ide_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_IDE;
+ k->revision = 0x06;
+ k->class_id = PCI_CLASS_STORAGE_IDE;
+ dc->no_user = 1;
+}
+
+static TypeInfo via_ide_info = {
+ .name = "via-ide",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIIDEState),
+ .class_init = via_ide_class_init,
};
static void via_ide_register(void)
{
- pci_qdev_register(&via_ide_info);
+ type_register_static(&via_ide_info);
}
device_init(via_ide_register);
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index e5712fc3e7..6dbd649908 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -518,20 +518,45 @@ static void integratorcp_machine_init(void)
machine_init(integratorcp_machine_init);
-static SysBusDeviceInfo core_info = {
- .init = integratorcm_init,
- .qdev.name = "integrator_core",
- .qdev.size = sizeof(integratorcm_state),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property core_properties[] = {
+ DEFINE_PROP_UINT32("memsz", integratorcm_state, memsz, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void core_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = integratorcm_init;
+ dc->props = core_properties;
+}
+
+static TypeInfo core_info = {
+ .name = "integrator_core",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(integratorcm_state),
+ .class_init = core_class_init,
+};
+
+static void icp_pic_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = icp_pic_init;
+}
+
+static TypeInfo icp_pic_info = {
+ .name = "integrator_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(icp_pic_state),
+ .class_init = icp_pic_class_init,
};
static void integratorcp_register_devices(void)
{
- sysbus_register_dev("integrator_pic", sizeof(icp_pic_state), icp_pic_init);
- sysbus_register_withprop(&core_info);
+ type_register_static(&icp_pic_info);
+ type_register_static(&core_info);
}
device_init(integratorcp_register_devices)
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index 10769e0f49..83c42d58b6 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -47,13 +47,12 @@ void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
bus->xfer = xfer;
}
-static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
+static int hda_codec_dev_init(DeviceState *qdev)
{
HDACodecBus *bus = DO_UPCAST(HDACodecBus, qbus, qdev->parent_bus);
HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- HDACodecDeviceInfo *info = DO_UPCAST(HDACodecDeviceInfo, qdev, base);
+ HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
- dev->info = info;
if (dev->cad == -1) {
dev->cad = bus->next_cad;
}
@@ -61,27 +60,20 @@ static int hda_codec_dev_init(DeviceState *qdev, DeviceInfo *base)
return -1;
}
bus->next_cad = dev->cad + 1;
- return info->init(dev);
+ return cdc->init(dev);
}
static int hda_codec_dev_exit(DeviceState *qdev)
{
HDACodecDevice *dev = DO_UPCAST(HDACodecDevice, qdev, qdev);
+ HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
- if (dev->info->exit) {
- dev->info->exit(dev);
+ if (cdc->exit) {
+ cdc->exit(dev);
}
return 0;
}
-void hda_codec_register(HDACodecDeviceInfo *info)
-{
- info->qdev.init = hda_codec_dev_init;
- info->qdev.exit = hda_codec_dev_exit;
- info->qdev.bus_info = &hda_codec_bus_info;
- qdev_register(&info->qdev);
-}
-
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
{
DeviceState *qdev;
@@ -283,6 +275,7 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
{
uint32_t cad, nid, data;
HDACodecDevice *codec;
+ HDACodecDeviceClass *cdc;
cad = (verb >> 28) & 0x0f;
if (verb & (1 << 27)) {
@@ -298,7 +291,8 @@ static int intel_hda_send_command(IntelHDAState *d, uint32_t verb)
dprint(d, 1, "%s: addressed non-existing codec\n", __FUNCTION__);
return -1;
}
- codec->info->command(codec, nid, data);
+ cdc = HDA_CODEC_DEVICE_GET_CLASS(codec);
+ cdc->command(codec, nid, data);
return 0;
}
@@ -491,9 +485,12 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
HDACodecDevice *cdev;
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ HDACodecDeviceClass *cdc;
+
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- if (cdev->info->stream) {
- cdev->info->stream(cdev, stream, running, output);
+ cdc = HDA_CODEC_DEVICE_GET_CLASS(cdev);
+ if (cdc->stream) {
+ cdc->stream(cdev, stream, running, output);
}
}
}
@@ -1116,9 +1113,7 @@ static void intel_hda_reset(DeviceState *dev)
/* reset codecs */
QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
- if (qdev->info->reset) {
- qdev->info->reset(qdev);
- }
+ device_reset(DEVICE(cdev));
d->state_sts |= (1 << cdev->cad);
}
intel_hda_update_irq(d);
@@ -1129,7 +1124,7 @@ static int intel_hda_init(PCIDevice *pci)
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
uint8_t *conf = d->pci.config;
- d->name = d->pci.qdev.info->name;
+ d->name = object_get_typename(OBJECT(d));
pci_config_set_interrupt_pin(conf, 1);
@@ -1244,29 +1239,58 @@ static const VMStateDescription vmstate_intel_hda = {
}
};
-static PCIDeviceInfo intel_hda_info = {
- .qdev.name = "intel-hda",
- .qdev.desc = "Intel HD Audio Controller",
- .qdev.size = sizeof(IntelHDAState),
- .qdev.vmsd = &vmstate_intel_hda,
- .qdev.reset = intel_hda_reset,
- .init = intel_hda_init,
- .exit = intel_hda_exit,
- .config_write = intel_hda_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = 0x2668,
- .revision = 1,
- .class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
- DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property intel_hda_properties[] = {
+ DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
+ DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void intel_hda_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = intel_hda_init;
+ k->exit = intel_hda_exit;
+ k->config_write = intel_hda_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = 0x2668;
+ k->revision = 1;
+ k->class_id = PCI_CLASS_MULTIMEDIA_HD_AUDIO;
+ dc->desc = "Intel HD Audio Controller";
+ dc->reset = intel_hda_reset;
+ dc->vmsd = &vmstate_intel_hda;
+ dc->props = intel_hda_properties;
+}
+
+static TypeInfo intel_hda_info = {
+ .name = "intel-hda",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(IntelHDAState),
+ .class_init = intel_hda_class_init,
+};
+
+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;
+ k->bus_info = &hda_codec_bus_info;
+}
+
+static TypeInfo hda_codec_device_type_info = {
+ .name = TYPE_HDA_CODEC_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(HDACodecDevice),
+ .abstract = true,
+ .class_size = sizeof(HDACodecDeviceClass),
+ .class_init = hda_codec_device_class_init,
};
static void intel_hda_register(void)
{
- pci_qdev_register(&intel_hda_info);
+ type_register_static(&intel_hda_info);
+ type_register_static(&hda_codec_device_type_info);
}
device_init(intel_hda_register);
diff --git a/hw/intel-hda.h b/hw/intel-hda.h
index 65fd2a85bb..a1cca5b1bb 100644
--- a/hw/intel-hda.h
+++ b/hw/intel-hda.h
@@ -6,9 +6,16 @@
/* --------------------------------------------------------------------- */
/* hda bus */
+#define TYPE_HDA_CODEC_DEVICE "hda-codec"
+#define HDA_CODEC_DEVICE(obj) \
+ OBJECT_CHECK(HDACodecDevice, (obj), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(HDACodecDeviceClass, (klass), TYPE_HDA_CODEC_DEVICE)
+#define HDA_CODEC_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(HDACodecDeviceClass, (obj), TYPE_HDA_CODEC_DEVICE)
+
typedef struct HDACodecBus HDACodecBus;
typedef struct HDACodecDevice HDACodecDevice;
-typedef struct HDACodecDeviceInfo HDACodecDeviceInfo;
typedef void (*hda_codec_response_func)(HDACodecDevice *dev,
bool solicited, uint32_t response);
@@ -23,24 +30,24 @@ struct HDACodecBus {
hda_codec_xfer_func xfer;
};
-struct HDACodecDevice {
- DeviceState qdev;
- HDACodecDeviceInfo *info;
- uint32_t cad; /* codec address */
-};
+typedef struct HDACodecDeviceClass
+{
+ DeviceClass parent_class;
-struct HDACodecDeviceInfo {
- DeviceInfo qdev;
int (*init)(HDACodecDevice *dev);
int (*exit)(HDACodecDevice *dev);
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
+} HDACodecDeviceClass;
+
+struct HDACodecDevice {
+ DeviceState qdev;
+ uint32_t cad; /* codec address */
};
void hda_codec_bus_init(DeviceState *dev, HDACodecBus *bus,
hda_codec_response_func response,
hda_codec_xfer_func xfer);
-void hda_codec_register(HDACodecDeviceInfo *info);
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad);
void hda_codec_response(HDACodecDevice *dev, bool solicited, uint32_t response);
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 27b07c6317..79549f8ed1 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -24,9 +24,7 @@
#include "pc.h"
#include "apic.h"
#include "ioapic.h"
-#include "qemu-timer.h"
-#include "host-utils.h"
-#include "sysbus.h"
+#include "ioapic_internal.h"
//#define DEBUG_IOAPIC
@@ -37,65 +35,9 @@
#define DPRINTF(fmt, ...)
#endif
-#define MAX_IOAPICS 1
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
-#define IOAPIC_VERSION 0x11
-
-#define IOAPIC_LVT_DEST_SHIFT 56
-#define IOAPIC_LVT_MASKED_SHIFT 16
-#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15
-#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14
-#define IOAPIC_LVT_POLARITY_SHIFT 13
-#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12
-#define IOAPIC_LVT_DEST_MODE_SHIFT 11
-#define IOAPIC_LVT_DELIV_MODE_SHIFT 8
-
-#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT)
-#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
-
-#define IOAPIC_TRIGGER_EDGE 0
-#define IOAPIC_TRIGGER_LEVEL 1
-
-/*io{apic,sapic} delivery mode*/
-#define IOAPIC_DM_FIXED 0x0
-#define IOAPIC_DM_LOWEST_PRIORITY 0x1
-#define IOAPIC_DM_PMI 0x2
-#define IOAPIC_DM_NMI 0x4
-#define IOAPIC_DM_INIT 0x5
-#define IOAPIC_DM_SIPI 0x6
-#define IOAPIC_DM_EXTINT 0x7
-#define IOAPIC_DM_MASK 0x7
-
-#define IOAPIC_VECTOR_MASK 0xff
-
-#define IOAPIC_IOREGSEL 0x00
-#define IOAPIC_IOWIN 0x10
-
-#define IOAPIC_REG_ID 0x00
-#define IOAPIC_REG_VER 0x01
-#define IOAPIC_REG_ARB 0x02
-#define IOAPIC_REG_REDTBL_BASE 0x10
-#define IOAPIC_ID 0x00
-
-#define IOAPIC_ID_SHIFT 24
-#define IOAPIC_ID_MASK 0xf
-
-#define IOAPIC_VER_ENTRIES_SHIFT 16
-
-typedef struct IOAPICState IOAPICState;
-
-struct IOAPICState {
- SysBusDevice busdev;
- MemoryRegion io_memory;
- uint8_t id;
- uint8_t ioregsel;
- uint32_t irr;
- uint64_t ioredtbl[IOAPIC_NUM_PINS];
-};
-
-static IOAPICState *ioapics[MAX_IOAPICS];
-
-static void ioapic_service(IOAPICState *s)
+static void ioapic_service(IOAPICCommonState *s)
{
uint8_t i;
uint8_t trig_mode;
@@ -135,7 +77,7 @@ static void ioapic_service(IOAPICState *s)
static void ioapic_set_irq(void *opaque, int vector, int level)
{
- IOAPICState *s = opaque;
+ IOAPICCommonState *s = opaque;
/* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
* to GSI 2. GSI maps to ioapic 1-1. This is not
@@ -174,7 +116,7 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
void ioapic_eoi_broadcast(int vector)
{
- IOAPICState *s;
+ IOAPICCommonState *s;
uint64_t entry;
int i, n;
@@ -199,7 +141,7 @@ void ioapic_eoi_broadcast(int vector)
static uint64_t
ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size)
{
- IOAPICState *s = opaque;
+ IOAPICCommonState *s = opaque;
int index;
uint32_t val = 0;
@@ -242,7 +184,7 @@ static void
ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
unsigned int size)
{
- IOAPICState *s = opaque;
+ IOAPICCommonState *s = opaque;
int index;
switch (addr & 0xff) {
@@ -278,83 +220,40 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
}
}
-static int ioapic_post_load(void *opaque, int version_id)
-{
- IOAPICState *s = opaque;
-
- if (version_id == 1) {
- /* set sane value */
- s->irr = 0;
- }
- return 0;
-}
-
-static const VMStateDescription vmstate_ioapic = {
- .name = "ioapic",
- .version_id = 3,
- .post_load = ioapic_post_load,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT8(id, IOAPICState),
- VMSTATE_UINT8(ioregsel, IOAPICState),
- VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
- VMSTATE_UINT32_V(irr, IOAPICState, 2),
- VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static void ioapic_reset(DeviceState *d)
-{
- IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d);
- int i;
-
- s->id = 0;
- s->ioregsel = 0;
- s->irr = 0;
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
- }
-}
-
static const MemoryRegionOps ioapic_io_ops = {
.read = ioapic_mem_read,
.write = ioapic_mem_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int ioapic_init1(SysBusDevice *dev)
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
{
- IOAPICState *s = FROM_SYSBUS(IOAPICState, dev);
- static int ioapic_no;
-
- if (ioapic_no >= MAX_IOAPICS) {
- return -1;
- }
-
memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
- sysbus_init_mmio(dev, &s->io_memory);
- qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+ qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+
+ ioapics[instance_no] = s;
+}
- ioapics[ioapic_no++] = s;
+static void ioapic_class_init(ObjectClass *klass, void *data)
+{
+ IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
- return 0;
+ k->init = ioapic_init;
+ dc->reset = ioapic_reset_common;
}
-static SysBusDeviceInfo ioapic_info = {
- .init = ioapic_init1,
- .qdev.name = "ioapic",
- .qdev.size = sizeof(IOAPICState),
- .qdev.vmsd = &vmstate_ioapic,
- .qdev.reset = ioapic_reset,
- .qdev.no_user = 1,
+static TypeInfo ioapic_info = {
+ .name = "ioapic",
+ .parent = TYPE_IOAPIC_COMMON,
+ .instance_size = sizeof(IOAPICCommonState),
+ .class_init = ioapic_class_init,
};
static void ioapic_register_devices(void)
{
- sysbus_register_withprop(&ioapic_info);
+ type_register_static(&ioapic_info);
}
device_init(ioapic_register_devices)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
new file mode 100644
index 0000000000..f932700d12
--- /dev/null
+++ b/hw/ioapic_common.c
@@ -0,0 +1,121 @@
+/*
+ * IOAPIC emulation logic - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2009 Xiantao Zhang, Intel
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ioapic.h"
+#include "ioapic_internal.h"
+#include "sysbus.h"
+
+void ioapic_reset_common(DeviceState *dev)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(dev);
+ int i;
+
+ s->id = 0;
+ s->ioregsel = 0;
+ s->irr = 0;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+ s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+ }
+}
+
+static void ioapic_dispatch_pre_save(void *opaque)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+ IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+ if (info->pre_save) {
+ info->pre_save(s);
+ }
+}
+
+static int ioapic_dispatch_post_load(void *opaque, int version_id)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(opaque);
+ IOAPICCommonClass *info = IOAPIC_COMMON_GET_CLASS(s);
+
+ if (info->post_load) {
+ info->post_load(s);
+ }
+ return 0;
+}
+
+static int ioapic_init_common(SysBusDevice *dev)
+{
+ IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+ IOAPICCommonClass *info;
+ static int ioapic_no;
+
+ if (ioapic_no >= MAX_IOAPICS) {
+ return -1;
+ }
+
+ info = IOAPIC_COMMON_GET_CLASS(s);
+ info->init(s, ioapic_no);
+
+ sysbus_init_mmio(&s->busdev, &s->io_memory);
+ ioapic_no++;
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_ioapic_common = {
+ .name = "ioapic",
+ .version_id = 3,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = ioapic_dispatch_pre_save,
+ .post_load = ioapic_dispatch_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(id, IOAPICCommonState),
+ VMSTATE_UINT8(ioregsel, IOAPICCommonState),
+ VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+ VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
+ VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void ioapic_common_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sc->init = ioapic_init_common;
+ dc->vmsd = &vmstate_ioapic_common;
+ dc->no_user = 1;
+}
+
+static TypeInfo ioapic_common_type = {
+ .name = TYPE_IOAPIC_COMMON,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IOAPICCommonState),
+ .class_size = sizeof(IOAPICCommonClass),
+ .class_init = ioapic_common_class_init,
+ .abstract = true,
+};
+
+static void register_devices(void)
+{
+ type_register_static(&ioapic_common_type);
+}
+
+device_init(register_devices);
+
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
new file mode 100644
index 0000000000..e04c9f3c12
--- /dev/null
+++ b/hw/ioapic_internal.h
@@ -0,0 +1,102 @@
+/*
+ * IOAPIC emulation logic - internal interfaces
+ *
+ * Copyright (c) 2004-2005 Fabrice Bellard
+ * Copyright (c) 2009 Xiantao Zhang, Intel
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_IOAPIC_INTERNAL_H
+#define QEMU_IOAPIC_INTERNAL_H
+
+#include "hw.h"
+#include "memory.h"
+#include "sysbus.h"
+
+#define MAX_IOAPICS 1
+
+#define IOAPIC_VERSION 0x11
+
+#define IOAPIC_LVT_DEST_SHIFT 56
+#define IOAPIC_LVT_MASKED_SHIFT 16
+#define IOAPIC_LVT_TRIGGER_MODE_SHIFT 15
+#define IOAPIC_LVT_REMOTE_IRR_SHIFT 14
+#define IOAPIC_LVT_POLARITY_SHIFT 13
+#define IOAPIC_LVT_DELIV_STATUS_SHIFT 12
+#define IOAPIC_LVT_DEST_MODE_SHIFT 11
+#define IOAPIC_LVT_DELIV_MODE_SHIFT 8
+
+#define IOAPIC_LVT_MASKED (1 << IOAPIC_LVT_MASKED_SHIFT)
+#define IOAPIC_LVT_REMOTE_IRR (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
+
+#define IOAPIC_TRIGGER_EDGE 0
+#define IOAPIC_TRIGGER_LEVEL 1
+
+/*io{apic,sapic} delivery mode*/
+#define IOAPIC_DM_FIXED 0x0
+#define IOAPIC_DM_LOWEST_PRIORITY 0x1
+#define IOAPIC_DM_PMI 0x2
+#define IOAPIC_DM_NMI 0x4
+#define IOAPIC_DM_INIT 0x5
+#define IOAPIC_DM_SIPI 0x6
+#define IOAPIC_DM_EXTINT 0x7
+#define IOAPIC_DM_MASK 0x7
+
+#define IOAPIC_VECTOR_MASK 0xff
+
+#define IOAPIC_IOREGSEL 0x00
+#define IOAPIC_IOWIN 0x10
+
+#define IOAPIC_REG_ID 0x00
+#define IOAPIC_REG_VER 0x01
+#define IOAPIC_REG_ARB 0x02
+#define IOAPIC_REG_REDTBL_BASE 0x10
+#define IOAPIC_ID 0x00
+
+#define IOAPIC_ID_SHIFT 24
+#define IOAPIC_ID_MASK 0xf
+
+#define IOAPIC_VER_ENTRIES_SHIFT 16
+
+typedef struct IOAPICCommonState IOAPICCommonState;
+
+#define TYPE_IOAPIC_COMMON "ioapic-common"
+#define IOAPIC_COMMON(obj) \
+ OBJECT_CHECK(IOAPICCommonState, (obj), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_CLASS(klass) \
+ OBJECT_CLASS_CHECK(IOAPICCommonClass, (klass), TYPE_IOAPIC_COMMON)
+#define IOAPIC_COMMON_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(IOAPICCommonClass, (obj), TYPE_IOAPIC_COMMON)
+
+typedef struct IOAPICCommonClass {
+ SysBusDeviceClass parent_class;
+ void (*init)(IOAPICCommonState *s, int instance_no);
+ void (*pre_save)(IOAPICCommonState *s);
+ void (*post_load)(IOAPICCommonState *s);
+} IOAPICCommonClass;
+
+struct IOAPICCommonState {
+ SysBusDevice busdev;
+ MemoryRegion io_memory;
+ uint8_t id;
+ uint8_t ioregsel;
+ uint32_t irr;
+ uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+void ioapic_reset_common(DeviceState *dev);
+
+#endif /* !QEMU_IOAPIC_INTERNAL_H */
diff --git a/hw/ioh3420.c b/hw/ioh3420.c
index a6bfbb9173..1c60123d43 100644
--- a/hw/ioh3420.c
+++ b/hw/ioh3420.c
@@ -80,7 +80,7 @@ static void ioh3420_write_config(PCIDevice *d,
static void ioh3420_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
msi_reset(d);
ioh3420_aer_vector_update(d);
pcie_cap_root_reset(d);
@@ -201,36 +201,45 @@ static const VMStateDescription vmstate_ioh3420 = {
}
};
-static PCIDeviceInfo ioh3420_info = {
- .qdev.name = "ioh3420",
- .qdev.desc = "Intel IOH device id 3420 PCIE Root Port",
- .qdev.size = sizeof(PCIESlot),
- .qdev.reset = ioh3420_reset,
- .qdev.vmsd = &vmstate_ioh3420,
-
- .is_express = 1,
- .is_bridge = 1,
- .config_write = ioh3420_write_config,
- .init = ioh3420_initfn,
- .exit = ioh3420_exitfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_IOH_EPORT,
- .revision = PCI_DEVICE_ID_IOH_REV,
-
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
- DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
- DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
- DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
- port.br.dev.exp.aer_log.log_max,
- PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ioh3420_properties[] = {
+ DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+ DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+ DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+ DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+ port.br.dev.exp.aer_log.log_max,
+ PCIE_AER_LOG_MAX_DEFAULT),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ioh3420_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->config_write = ioh3420_write_config;
+ k->init = ioh3420_initfn;
+ k->exit = ioh3420_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_IOH_EPORT;
+ k->revision = PCI_DEVICE_ID_IOH_REV;
+ dc->desc = "Intel IOH device id 3420 PCIE Root Port";
+ dc->reset = ioh3420_reset;
+ dc->vmsd = &vmstate_ioh3420;
+ dc->props = ioh3420_properties;
+}
+
+static TypeInfo ioh3420_info = {
+ .name = "ioh3420",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIESlot),
+ .class_init = ioh3420_class_init,
};
static void ioh3420_register(void)
{
- pci_qdev_register(&ioh3420_info);
+ type_register_static(&ioh3420_info);
}
device_init(ioh3420_register);
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 5af790bf81..d03f82824c 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -110,22 +110,19 @@ void isa_register_portio_list(ISADevice *dev, uint16_t start,
portio_list_add(piolist, isabus->address_space_io, start);
}
-static int isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int isa_qdev_init(DeviceState *qdev)
{
- ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev);
- ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, base);
+ ISADevice *dev = ISA_DEVICE(qdev);
+ ISADeviceClass *klass = ISA_DEVICE_GET_CLASS(dev);
dev->isairq[0] = -1;
dev->isairq[1] = -1;
- return info->init(dev);
-}
+ if (klass->init) {
+ return klass->init(dev);
+ }
-void isa_qdev_register(ISADeviceInfo *info)
-{
- info->qdev.init = isa_qdev_init;
- info->qdev.bus_info = &isa_bus_info;
- qdev_register(&info->qdev);
+ return 0;
}
ISADevice *isa_create(ISABus *bus, const char *name)
@@ -137,7 +134,7 @@ ISADevice *isa_create(ISABus *bus, const char *name)
name);
}
dev = qdev_create(&bus->qbus, name);
- return DO_UPCAST(ISADevice, qdev, dev);
+ return ISA_DEVICE(dev);
}
ISADevice *isa_try_create(ISABus *bus, const char *name)
@@ -149,7 +146,7 @@ ISADevice *isa_try_create(ISABus *bus, const char *name)
name);
}
dev = qdev_try_create(&bus->qbus, name);
- return DO_UPCAST(ISADevice, qdev, dev);
+ return ISA_DEVICE(dev);
}
ISADevice *isa_create_simple(ISABus *bus, const char *name)
@@ -163,7 +160,7 @@ ISADevice *isa_create_simple(ISABus *bus, const char *name)
static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
{
- ISADevice *d = DO_UPCAST(ISADevice, qdev, dev);
+ ISADevice *d = ISA_DEVICE(dev);
if (d->isairq[1] != -1) {
monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
@@ -180,17 +177,43 @@ static int isabus_bridge_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo isabus_bridge_info = {
- .init = isabus_bridge_init,
- .qdev.name = "isabus-bridge",
- .qdev.fw_name = "isa",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
+static void isabus_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = isabus_bridge_init;
+ dc->fw_name = "isa";
+ dc->no_user = 1;
+}
+
+static TypeInfo isabus_bridge_info = {
+ .name = "isabus-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = isabus_bridge_class_init,
+};
+
+static void isa_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = isa_qdev_init;
+ k->bus_info = &isa_bus_info;
+}
+
+static TypeInfo isa_device_type_info = {
+ .name = TYPE_ISA_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(ISADevice),
+ .abstract = true,
+ .class_size = sizeof(ISADeviceClass),
+ .class_init = isa_device_class_init,
};
static void isabus_register_devices(void)
{
- sysbus_register_withprop(&isabus_bridge_info);
+ type_register_static(&isabus_bridge_info);
+ type_register_static(&isa_device_type_info);
}
static char *isabus_get_fw_dev_path(DeviceState *dev)
diff --git a/hw/isa.h b/hw/isa.h
index b11a0be27f..40373fb107 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -10,7 +10,19 @@
#define ISA_NUM_IRQS 16
typedef struct ISADevice ISADevice;
-typedef struct ISADeviceInfo ISADeviceInfo;
+
+#define TYPE_ISA_DEVICE "isa-device"
+#define ISA_DEVICE(obj) \
+ OBJECT_CHECK(ISADevice, (obj), TYPE_ISA_DEVICE)
+#define ISA_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(ISADeviceClass, (klass), TYPE_ISA_DEVICE)
+#define ISA_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(ISADeviceClass, (obj), TYPE_ISA_DEVICE)
+
+typedef struct ISADeviceClass {
+ DeviceClass parent_class;
+ int (*init)(ISADevice *dev);
+} ISADeviceClass;
struct ISABus {
BusState qbus;
@@ -25,17 +37,10 @@ struct ISADevice {
int ioport_id;
};
-typedef int (*isa_qdev_initfn)(ISADevice *dev);
-struct ISADeviceInfo {
- DeviceInfo qdev;
- isa_qdev_initfn init;
-};
-
ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io);
void isa_bus_irqs(ISABus *bus, qemu_irq *irqs);
qemu_irq isa_get_irq(ISADevice *dev, int isairq);
void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq);
-void isa_qdev_register(ISADeviceInfo *info);
MemoryRegion *isa_address_space(ISADevice *dev);
ISADevice *isa_create(ISABus *bus, const char *name);
ISADevice *isa_try_create(ISABus *bus, const char *name);
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index bec2e0b8fe..6f017d474c 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -766,30 +766,41 @@ static int pci_ivshmem_uninit(PCIDevice *dev)
return 0;
}
-static PCIDeviceInfo ivshmem_info = {
- .qdev.name = "ivshmem",
- .qdev.size = sizeof(IVShmemState),
- .qdev.reset = ivshmem_reset,
- .init = pci_ivshmem_init,
- .exit = pci_ivshmem_uninit,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = 0x1110,
- .class_id = PCI_CLASS_MEMORY_RAM,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
- DEFINE_PROP_STRING("size", IVShmemState, sizearg),
- DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
- DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
- DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
- DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
- DEFINE_PROP_STRING("role", IVShmemState, role),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ivshmem_properties[] = {
+ DEFINE_PROP_CHR("chardev", IVShmemState, server_chr),
+ DEFINE_PROP_STRING("size", IVShmemState, sizearg),
+ DEFINE_PROP_UINT32("vectors", IVShmemState, vectors, 1),
+ DEFINE_PROP_BIT("ioeventfd", IVShmemState, features, IVSHMEM_IOEVENTFD, false),
+ DEFINE_PROP_BIT("msi", IVShmemState, features, IVSHMEM_MSI, true),
+ DEFINE_PROP_STRING("shm", IVShmemState, shmobj),
+ DEFINE_PROP_STRING("role", IVShmemState, role),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ivshmem_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ivshmem_init;
+ k->exit = pci_ivshmem_uninit;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = 0x1110;
+ k->class_id = PCI_CLASS_MEMORY_RAM;
+ dc->reset = ivshmem_reset;
+ dc->props = ivshmem_properties;
+}
+
+static TypeInfo ivshmem_info = {
+ .name = "ivshmem",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(IVShmemState),
+ .class_init = ivshmem_class_init,
};
static void ivshmem_register_devices(void)
{
- pci_qdev_register(&ivshmem_info);
+ type_register_static(&ivshmem_info);
}
device_init(ivshmem_register_devices)
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
new file mode 100644
index 0000000000..dfc2ab3b03
--- /dev/null
+++ b/hw/kvm/apic.c
@@ -0,0 +1,147 @@
+/*
+ * KVM in-kernel APIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
+ int reg_id, uint32_t val)
+{
+ *((uint32_t *)(kapic->regs + (reg_id << 4))) = val;
+}
+
+static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
+ int reg_id)
+{
+ return *((uint32_t *)(kapic->regs + (reg_id << 4)));
+}
+
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ int i;
+
+ memset(kapic, 0, sizeof(kapic));
+ kvm_apic_set_reg(kapic, 0x2, s->id << 24);
+ kvm_apic_set_reg(kapic, 0x8, s->tpr);
+ kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
+ kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
+ kvm_apic_set_reg(kapic, 0xf, s->spurious_vec);
+ for (i = 0; i < 8; i++) {
+ kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]);
+ kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]);
+ kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]);
+ }
+ kvm_apic_set_reg(kapic, 0x28, s->esr);
+ kvm_apic_set_reg(kapic, 0x30, s->icr[0]);
+ kvm_apic_set_reg(kapic, 0x31, s->icr[1]);
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]);
+ }
+ kvm_apic_set_reg(kapic, 0x38, s->initial_count);
+ kvm_apic_set_reg(kapic, 0x3e, s->divide_conf);
+}
+
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+ APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+ int i, v;
+
+ s->id = kvm_apic_get_reg(kapic, 0x2) >> 24;
+ s->tpr = kvm_apic_get_reg(kapic, 0x8);
+ s->arb_id = kvm_apic_get_reg(kapic, 0x9);
+ s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24;
+ s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28;
+ s->spurious_vec = kvm_apic_get_reg(kapic, 0xf);
+ for (i = 0; i < 8; i++) {
+ s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i);
+ s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i);
+ s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i);
+ }
+ s->esr = kvm_apic_get_reg(kapic, 0x28);
+ s->icr[0] = kvm_apic_get_reg(kapic, 0x30);
+ s->icr[1] = kvm_apic_get_reg(kapic, 0x31);
+ for (i = 0; i < APIC_LVT_NB; i++) {
+ s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i);
+ }
+ s->initial_count = kvm_apic_get_reg(kapic, 0x38);
+ s->divide_conf = kvm_apic_get_reg(kapic, 0x3e);
+
+ v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+ s->count_shift = (v + 1) & 7;
+
+ s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+ apic_next_timer(s, s->initial_count_load_time);
+}
+
+static void kvm_apic_set_base(APICCommonState *s, uint64_t val)
+{
+ s->apicbase = val;
+}
+
+static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+ s->tpr = (val & 0x0f) << 4;
+}
+
+static void do_inject_external_nmi(void *data)
+{
+ APICCommonState *s = data;
+ CPUState *env = s->cpu_env;
+ uint32_t lvt;
+ int ret;
+
+ cpu_synchronize_state(env);
+
+ lvt = s->lvt[APIC_LVT_LINT1];
+ if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
+ ret = kvm_vcpu_ioctl(env, KVM_NMI);
+ if (ret < 0) {
+ fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
+ strerror(-ret));
+ }
+ }
+}
+
+static void kvm_apic_external_nmi(APICCommonState *s)
+{
+ run_on_cpu(s->cpu_env, do_inject_external_nmi, s);
+}
+
+static void kvm_apic_init(APICCommonState *s)
+{
+ memory_region_init_reservation(&s->io_memory, "kvm-apic-msi",
+ MSI_SPACE_SIZE);
+}
+
+static void kvm_apic_class_init(ObjectClass *klass, void *data)
+{
+ APICCommonClass *k = APIC_COMMON_CLASS(klass);
+
+ k->init = kvm_apic_init;
+ k->set_base = kvm_apic_set_base;
+ k->set_tpr = kvm_apic_set_tpr;
+ k->external_nmi = kvm_apic_external_nmi;
+}
+
+static TypeInfo kvm_apic_info = {
+ .name = "kvm-apic",
+ .parent = TYPE_APIC_COMMON,
+ .instance_size = sizeof(APICCommonState),
+ .class_init = kvm_apic_class_init,
+};
+
+static void kvm_apic_register_device(void)
+{
+ type_register_static(&kvm_apic_info);
+}
+
+device_init(kvm_apic_register_device)
diff --git a/hw/kvmclock.c b/hw/kvm/clock.c
index 3b9fb20495..d5a53869b3 100644
--- a/hw/kvmclock.c
+++ b/hw/kvm/clock.c
@@ -15,9 +15,9 @@
#include "qemu-common.h"
#include "sysemu.h"
-#include "sysbus.h"
#include "kvm.h"
-#include "kvmclock.h"
+#include "hw/sysbus.h"
+#include "hw/kvm/clock.h"
#include <linux/kvm.h>
#include <linux/kvm_para.h>
@@ -92,12 +92,21 @@ static const VMStateDescription kvmclock_vmsd = {
}
};
-static SysBusDeviceInfo kvmclock_info = {
- .qdev.name = "kvmclock",
- .qdev.size = sizeof(KVMClockState),
- .qdev.vmsd = &kvmclock_vmsd,
- .qdev.no_user = 1,
- .init = kvmclock_init,
+static void kvmclock_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = kvmclock_init;
+ dc->no_user = 1;
+ dc->vmsd = &kvmclock_vmsd;
+}
+
+static TypeInfo kvmclock_info = {
+ .name = "kvmclock",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(KVMClockState),
+ .class_init = kvmclock_class_init,
};
/* Note: Must be called after VCPU initialization. */
@@ -113,7 +122,7 @@ void kvmclock_create(void)
static void kvmclock_register_device(void)
{
if (kvm_enabled()) {
- sysbus_register_withprop(&kvmclock_info);
+ type_register_static(&kvmclock_info);
}
}
diff --git a/hw/kvmclock.h b/hw/kvm/clock.h
index 252ea13461..252ea13461 100644
--- a/hw/kvmclock.h
+++ b/hw/kvm/clock.h
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
new file mode 100644
index 0000000000..14bd427518
--- /dev/null
+++ b/hw/kvm/i8259.c
@@ -0,0 +1,138 @@
+/*
+ * KVM in-kernel PIC (i8259) support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/i8259_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+static void kvm_pic_get(PICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_pic_state *kpic;
+ int ret;
+
+ chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+
+ kpic = &chip.chip.pic;
+
+ s->last_irr = kpic->last_irr;
+ s->irr = kpic->irr;
+ s->imr = kpic->imr;
+ s->isr = kpic->isr;
+ s->priority_add = kpic->priority_add;
+ s->irq_base = kpic->irq_base;
+ s->read_reg_select = kpic->read_reg_select;
+ s->poll = kpic->poll;
+ s->special_mask = kpic->special_mask;
+ s->init_state = kpic->init_state;
+ s->auto_eoi = kpic->auto_eoi;
+ s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
+ s->special_fully_nested_mode = kpic->special_fully_nested_mode;
+ s->init4 = kpic->init4;
+ s->elcr = kpic->elcr;
+ s->elcr_mask = kpic->elcr_mask;
+}
+
+static void kvm_pic_put(PICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_pic_state *kpic;
+ int ret;
+
+ chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+
+ kpic = &chip.chip.pic;
+
+ kpic->last_irr = s->last_irr;
+ kpic->irr = s->irr;
+ kpic->imr = s->imr;
+ kpic->isr = s->isr;
+ kpic->priority_add = s->priority_add;
+ kpic->irq_base = s->irq_base;
+ kpic->read_reg_select = s->read_reg_select;
+ kpic->poll = s->poll;
+ kpic->special_mask = s->special_mask;
+ kpic->init_state = s->init_state;
+ kpic->auto_eoi = s->auto_eoi;
+ kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
+ kpic->special_fully_nested_mode = s->special_fully_nested_mode;
+ kpic->init4 = s->init4;
+ kpic->elcr = s->elcr;
+ kpic->elcr_mask = s->elcr_mask;
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+}
+
+static void kvm_pic_reset(DeviceState *dev)
+{
+ PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, dev);
+
+ pic_reset_common(s);
+ s->elcr = 0;
+
+ kvm_pic_put(s);
+}
+
+static void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+ int delivered;
+
+ delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
+ apic_report_irq_delivered(delivered);
+}
+
+static void kvm_pic_init(PICCommonState *s)
+{
+ memory_region_init_reservation(&s->base_io, "kvm-pic", 2);
+ memory_region_init_reservation(&s->elcr_io, "kvm-elcr", 1);
+}
+
+qemu_irq *kvm_i8259_init(ISABus *bus)
+{
+ i8259_init_chip("kvm-i8259", bus, true);
+ i8259_init_chip("kvm-i8259", bus, false);
+
+ return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
+}
+
+static void kvm_i8259_class_init(ObjectClass *klass, void *data)
+{
+ PICCommonClass *k = PIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = kvm_pic_reset;
+ k->init = kvm_pic_init;
+ k->pre_save = kvm_pic_get;
+ k->post_load = kvm_pic_put;
+}
+
+static TypeInfo kvm_i8259_info = {
+ .name = "kvm-i8259",
+ .parent = TYPE_PIC_COMMON,
+ .instance_size = sizeof(PICCommonState),
+ .class_init = kvm_i8259_class_init,
+};
+
+static void kvm_pic_register(void)
+{
+ type_register_static(&kvm_i8259_info);
+}
+
+device_init(kvm_pic_register)
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
new file mode 100644
index 0000000000..b316933a96
--- /dev/null
+++ b/hw/kvm/ioapic.c
@@ -0,0 +1,125 @@
+/*
+ * KVM in-kernel IOPIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/pc.h"
+#include "hw/ioapic_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMIOAPICState KVMIOAPICState;
+
+struct KVMIOAPICState {
+ IOAPICCommonState ioapic;
+ uint32_t kvm_gsi_base;
+};
+
+static void kvm_ioapic_get(IOAPICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_ioapic_state *kioapic;
+ int ret, i;
+
+ chip.chip_id = KVM_IRQCHIP_IOAPIC;
+ ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+
+ kioapic = &chip.chip.ioapic;
+
+ s->id = kioapic->id;
+ s->ioregsel = kioapic->ioregsel;
+ s->irr = kioapic->irr;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+ s->ioredtbl[i] = kioapic->redirtbl[i].bits;
+ }
+}
+
+static void kvm_ioapic_put(IOAPICCommonState *s)
+{
+ struct kvm_irqchip chip;
+ struct kvm_ioapic_state *kioapic;
+ int ret, i;
+
+ chip.chip_id = KVM_IRQCHIP_IOAPIC;
+ kioapic = &chip.chip.ioapic;
+
+ kioapic->id = s->id;
+ kioapic->ioregsel = s->ioregsel;
+ kioapic->base_address = s->busdev.mmio[0].addr;
+ kioapic->irr = s->irr;
+ for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+ kioapic->redirtbl[i].bits = s->ioredtbl[i];
+ }
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+ if (ret < 0) {
+ fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+ abort();
+ }
+}
+
+static void kvm_ioapic_reset(DeviceState *dev)
+{
+ IOAPICCommonState *s = DO_UPCAST(IOAPICCommonState, busdev.qdev, dev);
+
+ ioapic_reset_common(dev);
+ kvm_ioapic_put(s);
+}
+
+static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
+{
+ KVMIOAPICState *s = opaque;
+ int delivered;
+
+ delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+ apic_report_irq_delivered(delivered);
+}
+
+static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+ memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000);
+
+ qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
+}
+
+static Property kvm_ioapic_properties[] = {
+ DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
+ DEFINE_PROP_END_OF_LIST()
+};
+
+static void kvm_ioapic_class_init(ObjectClass *klass, void *data)
+{
+ IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = kvm_ioapic_init;
+ k->pre_save = kvm_ioapic_get;
+ k->post_load = kvm_ioapic_put;
+ dc->reset = kvm_ioapic_reset;
+ dc->props = kvm_ioapic_properties;
+}
+
+static TypeInfo kvm_ioapic_info = {
+ .name = "kvm-ioapic",
+ .parent = TYPE_IOAPIC_COMMON,
+ .instance_size = sizeof(KVMIOAPICState),
+ .class_init = kvm_ioapic_class_init,
+};
+
+static void kvm_ioapic_register_device(void)
+{
+ type_register_static(&kvm_ioapic_info);
+}
+
+device_init(kvm_ioapic_register_device)
diff --git a/hw/lan9118.c b/hw/lan9118.c
index 8b83fe2198..78777c7336 100644
--- a/hw/lan9118.c
+++ b/hw/lan9118.c
@@ -140,17 +140,36 @@ enum tx_state {
};
typedef struct {
- enum tx_state state;
+ /* state is a tx_state but we can't put enums in VMStateDescriptions. */
+ uint32_t state;
uint32_t cmd_a;
uint32_t cmd_b;
- int buffer_size;
- int offset;
- int pad;
- int fifo_used;
- int len;
+ int32_t buffer_size;
+ int32_t offset;
+ int32_t pad;
+ int32_t fifo_used;
+ int32_t len;
uint8_t data[2048];
} LAN9118Packet;
+static const VMStateDescription vmstate_lan9118_packet = {
+ .name = "lan9118_packet",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(state, LAN9118Packet),
+ VMSTATE_UINT32(cmd_a, LAN9118Packet),
+ VMSTATE_UINT32(cmd_b, LAN9118Packet),
+ VMSTATE_INT32(buffer_size, LAN9118Packet),
+ VMSTATE_INT32(offset, LAN9118Packet),
+ VMSTATE_INT32(pad, LAN9118Packet),
+ VMSTATE_INT32(fifo_used, LAN9118Packet),
+ VMSTATE_INT32(len, LAN9118Packet),
+ VMSTATE_UINT8_ARRAY(data, LAN9118Packet, 2048),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
typedef struct {
SysBusDevice busdev;
NICState *nic;
@@ -190,34 +209,95 @@ typedef struct {
uint32_t phy_int;
uint32_t phy_int_mask;
- int eeprom_writable;
+ int32_t eeprom_writable;
uint8_t eeprom[128];
- int tx_fifo_size;
+ int32_t tx_fifo_size;
LAN9118Packet *txp;
LAN9118Packet tx_packet;
- int tx_status_fifo_used;
- int tx_status_fifo_head;
+ int32_t tx_status_fifo_used;
+ int32_t tx_status_fifo_head;
uint32_t tx_status_fifo[512];
- int rx_status_fifo_size;
- int rx_status_fifo_used;
- int rx_status_fifo_head;
+ int32_t rx_status_fifo_size;
+ int32_t rx_status_fifo_used;
+ int32_t rx_status_fifo_head;
uint32_t rx_status_fifo[896];
- int rx_fifo_size;
- int rx_fifo_used;
- int rx_fifo_head;
+ int32_t rx_fifo_size;
+ int32_t rx_fifo_used;
+ int32_t rx_fifo_head;
uint32_t rx_fifo[3360];
- int rx_packet_size_head;
- int rx_packet_size_tail;
- int rx_packet_size[1024];
+ int32_t rx_packet_size_head;
+ int32_t rx_packet_size_tail;
+ int32_t rx_packet_size[1024];
- int rxp_offset;
- int rxp_size;
- int rxp_pad;
+ int32_t rxp_offset;
+ int32_t rxp_size;
+ int32_t rxp_pad;
} lan9118_state;
+static const VMStateDescription vmstate_lan9118 = {
+ .name = "lan9118",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PTIMER(timer, lan9118_state),
+ VMSTATE_UINT32(irq_cfg, lan9118_state),
+ VMSTATE_UINT32(int_sts, lan9118_state),
+ VMSTATE_UINT32(int_en, lan9118_state),
+ VMSTATE_UINT32(fifo_int, lan9118_state),
+ VMSTATE_UINT32(rx_cfg, lan9118_state),
+ VMSTATE_UINT32(tx_cfg, lan9118_state),
+ VMSTATE_UINT32(hw_cfg, lan9118_state),
+ VMSTATE_UINT32(pmt_ctrl, lan9118_state),
+ VMSTATE_UINT32(gpio_cfg, lan9118_state),
+ VMSTATE_UINT32(gpt_cfg, lan9118_state),
+ VMSTATE_UINT32(word_swap, lan9118_state),
+ VMSTATE_UINT32(free_timer_start, lan9118_state),
+ VMSTATE_UINT32(mac_cmd, lan9118_state),
+ VMSTATE_UINT32(mac_data, lan9118_state),
+ VMSTATE_UINT32(afc_cfg, lan9118_state),
+ VMSTATE_UINT32(e2p_cmd, lan9118_state),
+ VMSTATE_UINT32(e2p_data, lan9118_state),
+ VMSTATE_UINT32(mac_cr, lan9118_state),
+ VMSTATE_UINT32(mac_hashh, lan9118_state),
+ VMSTATE_UINT32(mac_hashl, lan9118_state),
+ VMSTATE_UINT32(mac_mii_acc, lan9118_state),
+ VMSTATE_UINT32(mac_mii_data, lan9118_state),
+ VMSTATE_UINT32(mac_flow, lan9118_state),
+ VMSTATE_UINT32(phy_status, lan9118_state),
+ VMSTATE_UINT32(phy_control, lan9118_state),
+ VMSTATE_UINT32(phy_advertise, lan9118_state),
+ VMSTATE_UINT32(phy_int, lan9118_state),
+ VMSTATE_UINT32(phy_int_mask, lan9118_state),
+ VMSTATE_INT32(eeprom_writable, lan9118_state),
+ VMSTATE_UINT8_ARRAY(eeprom, lan9118_state, 128),
+ VMSTATE_INT32(tx_fifo_size, lan9118_state),
+ /* txp always points at tx_packet so need not be saved */
+ VMSTATE_STRUCT(tx_packet, lan9118_state, 0,
+ vmstate_lan9118_packet, LAN9118Packet),
+ VMSTATE_INT32(tx_status_fifo_used, lan9118_state),
+ VMSTATE_INT32(tx_status_fifo_head, lan9118_state),
+ VMSTATE_UINT32_ARRAY(tx_status_fifo, lan9118_state, 512),
+ VMSTATE_INT32(rx_status_fifo_size, lan9118_state),
+ VMSTATE_INT32(rx_status_fifo_used, lan9118_state),
+ VMSTATE_INT32(rx_status_fifo_head, lan9118_state),
+ VMSTATE_UINT32_ARRAY(rx_status_fifo, lan9118_state, 896),
+ VMSTATE_INT32(rx_fifo_size, lan9118_state),
+ VMSTATE_INT32(rx_fifo_used, lan9118_state),
+ VMSTATE_INT32(rx_fifo_head, lan9118_state),
+ VMSTATE_UINT32_ARRAY(rx_fifo, lan9118_state, 3360),
+ VMSTATE_INT32(rx_packet_size_head, lan9118_state),
+ VMSTATE_INT32(rx_packet_size_tail, lan9118_state),
+ VMSTATE_INT32_ARRAY(rx_packet_size, lan9118_state, 1024),
+ VMSTATE_INT32(rxp_offset, lan9118_state),
+ VMSTATE_INT32(rxp_size, lan9118_state),
+ VMSTATE_INT32(rxp_pad, lan9118_state),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static void lan9118_update(lan9118_state *s)
{
int level;
@@ -1141,7 +1221,7 @@ static int lan9118_init1(SysBusDevice *dev)
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
s->eeprom[0] = 0xa5;
for (i = 0; i < 6; i++) {
@@ -1155,24 +1235,35 @@ static int lan9118_init1(SysBusDevice *dev)
ptimer_set_freq(s->timer, 10000);
ptimer_set_limit(s->timer, 0xffff, 1);
- /* ??? Save/restore. */
return 0;
}
-static SysBusDeviceInfo lan9118_info = {
- .init = lan9118_init1,
- .qdev.name = "lan9118",
- .qdev.size = sizeof(lan9118_state),
- .qdev.reset = lan9118_reset,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(lan9118_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lan9118_properties[] = {
+ DEFINE_NIC_PROPERTIES(lan9118_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lan9118_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lan9118_init1;
+ dc->reset = lan9118_reset;
+ dc->props = lan9118_properties;
+ dc->vmsd = &vmstate_lan9118;
+}
+
+static TypeInfo lan9118_info = {
+ .name = "lan9118",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(lan9118_state),
+ .class_init = lan9118_class_init,
};
static void lan9118_register_devices(void)
{
- sysbus_register_withprop(&lan9118_info);
+ type_register_static(&lan9118_info);
}
/* Legacy helper function. Should go away when machine config files are
diff --git a/hw/lance.c b/hw/lance.c
index 716470061c..519720bd9c 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -137,22 +137,33 @@ static void lance_reset(DeviceState *dev)
pcnet_h_reset(&d->state);
}
-static SysBusDeviceInfo lance_info = {
- .init = lance_init,
- .qdev.name = "lance",
- .qdev.fw_name = "ethernet",
- .qdev.size = sizeof(SysBusPCNetState),
- .qdev.reset = lance_reset,
- .qdev.vmsd = &vmstate_lance,
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
- DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lance_properties[] = {
+ DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+ DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lance_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lance_init;
+ dc->fw_name = "ethernet";
+ dc->reset = lance_reset;
+ dc->vmsd = &vmstate_lance;
+ dc->props = lance_properties;
+}
+
+static TypeInfo lance_info = {
+ .name = "lance",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusPCNetState),
+ .class_init = lance_class_init,
};
static void lance_register_devices(void)
{
- sysbus_register_withprop(&lance_info);
+ type_register_static(&lance_info);
}
device_init(lance_register_devices)
diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
index 5454aa4e4d..38dd28230d 100644
--- a/hw/lm32_juart.c
+++ b/hw/lm32_juart.c
@@ -114,7 +114,7 @@ static int lm32_juart_init(SysBusDevice *dev)
{
LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr) {
qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
}
@@ -134,17 +134,26 @@ static const VMStateDescription vmstate_lm32_juart = {
}
};
-static SysBusDeviceInfo lm32_juart_info = {
- .init = lm32_juart_init,
- .qdev.name = "lm32-juart",
- .qdev.size = sizeof(LM32JuartState),
- .qdev.vmsd = &vmstate_lm32_juart,
- .qdev.reset = juart_reset,
+static void lm32_juart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_juart_init;
+ dc->reset = juart_reset;
+ dc->vmsd = &vmstate_lm32_juart;
+}
+
+static TypeInfo lm32_juart_info = {
+ .name = "lm32-juart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32JuartState),
+ .class_init = lm32_juart_class_init,
};
static void lm32_juart_register(void)
{
- sysbus_register_withprop(&lm32_juart_info);
+ type_register_static(&lm32_juart_info);
}
device_init(lm32_juart_register)
diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
index 8dd005077c..7be6d0d68e 100644
--- a/hw/lm32_pic.c
+++ b/hw/lm32_pic.c
@@ -174,17 +174,26 @@ static const VMStateDescription vmstate_lm32_pic = {
}
};
-static SysBusDeviceInfo lm32_pic_info = {
- .init = lm32_pic_init,
- .qdev.name = "lm32-pic",
- .qdev.size = sizeof(LM32PicState),
- .qdev.vmsd = &vmstate_lm32_pic,
- .qdev.reset = pic_reset,
+static void lm32_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_pic_init;
+ dc->reset = pic_reset;
+ dc->vmsd = &vmstate_lm32_pic;
+}
+
+static TypeInfo lm32_pic_info = {
+ .name = "lm32-pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32PicState),
+ .class_init = lm32_pic_class_init,
};
static void lm32_pic_register(void)
{
- sysbus_register_withprop(&lm32_pic_info);
+ type_register_static(&lm32_pic_info);
}
device_init(lm32_pic_register)
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
index 83974ee4fb..ba6f4acbaa 100644
--- a/hw/lm32_sys.c
+++ b/hw/lm32_sys.c
@@ -141,21 +141,32 @@ static const VMStateDescription vmstate_lm32_sys = {
}
};
-static SysBusDeviceInfo lm32_sys_info = {
- .init = lm32_sys_init,
- .qdev.name = "lm32-sys",
- .qdev.size = sizeof(LM32SysState),
- .qdev.vmsd = &vmstate_lm32_sys,
- .qdev.reset = sys_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lm32_sys_properties[] = {
+ DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_sys_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_sys_init;
+ dc->reset = sys_reset;
+ dc->vmsd = &vmstate_lm32_sys;
+ dc->props = lm32_sys_properties;
+}
+
+static TypeInfo lm32_sys_info = {
+ .name = "lm32-sys",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32SysState),
+ .class_init = lm32_sys_class_init,
};
static void lm32_sys_register(void)
{
- sysbus_register_withprop(&lm32_sys_info);
+ type_register_static(&lm32_sys_info);
}
device_init(lm32_sys_register)
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
index 115e1e968f..3cb4e0a4f3 100644
--- a/hw/lm32_timer.c
+++ b/hw/lm32_timer.c
@@ -199,23 +199,32 @@ static const VMStateDescription vmstate_lm32_timer = {
}
};
-static SysBusDeviceInfo lm32_timer_info = {
- .init = lm32_timer_init,
- .qdev.name = "lm32-timer",
- .qdev.size = sizeof(LM32TimerState),
- .qdev.vmsd = &vmstate_lm32_timer,
- .qdev.reset = timer_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32(
- "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY
- ),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property lm32_timer_properties[] = {
+ DEFINE_PROP_UINT32("frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lm32_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_timer_init;
+ dc->reset = timer_reset;
+ dc->vmsd = &vmstate_lm32_timer;
+ dc->props = lm32_timer_properties;
+}
+
+static TypeInfo lm32_timer_info = {
+ .name = "lm32-timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32TimerState),
+ .class_init = lm32_timer_class_init,
};
static void lm32_timer_register(void)
{
- sysbus_register_withprop(&lm32_timer_info);
+ type_register_static(&lm32_timer_info);
}
device_init(lm32_timer_register)
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
index d013abd1c6..630ccb7131 100644
--- a/hw/lm32_uart.c
+++ b/hw/lm32_uart.c
@@ -252,7 +252,7 @@ static int lm32_uart_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, &uart_ops, s, "uart", R_MAX * 4);
sysbus_init_mmio(dev, &s->iomem);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr) {
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
}
@@ -271,17 +271,26 @@ static const VMStateDescription vmstate_lm32_uart = {
}
};
-static SysBusDeviceInfo lm32_uart_info = {
- .init = lm32_uart_init,
- .qdev.name = "lm32-uart",
- .qdev.size = sizeof(LM32UartState),
- .qdev.vmsd = &vmstate_lm32_uart,
- .qdev.reset = uart_reset,
+static void lm32_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = lm32_uart_init;
+ dc->reset = uart_reset;
+ dc->vmsd = &vmstate_lm32_uart;
+}
+
+static TypeInfo lm32_uart_info = {
+ .name = "lm32-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(LM32UartState),
+ .class_init = lm32_uart_class_init,
};
static void lm32_uart_register(void)
{
- sysbus_register_withprop(&lm32_uart_info);
+ type_register_static(&lm32_uart_info);
}
device_init(lm32_uart_register)
diff --git a/hw/lm832x.c b/hw/lm832x.c
index 992ce49729..895d306635 100644
--- a/hw/lm832x.c
+++ b/hw/lm832x.c
@@ -24,7 +24,7 @@
#include "console.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
uint8_t i2c_dir;
uint8_t i2c_cycle;
uint8_t reg;
@@ -378,7 +378,7 @@ static void lm_kbd_write(LM823KbdState *s, int reg, int byte, uint8_t value)
}
}
-static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event)
+static void lm_i2c_event(I2CSlave *i2c, enum i2c_event event)
{
LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
@@ -394,14 +394,14 @@ static void lm_i2c_event(i2c_slave *i2c, enum i2c_event event)
}
}
-static int lm_i2c_rx(i2c_slave *i2c)
+static int lm_i2c_rx(I2CSlave *i2c)
{
LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
return lm_kbd_read(s, s->reg, s->i2c_cycle ++);
}
-static int lm_i2c_tx(i2c_slave *i2c, uint8_t data)
+static int lm_i2c_tx(I2CSlave *i2c, uint8_t data)
{
LM823KbdState *s = (LM823KbdState *) i2c;
@@ -458,7 +458,7 @@ static const VMStateDescription vmstate_lm_kbd = {
};
-static int lm8323_init(i2c_slave *i2c)
+static int lm8323_init(I2CSlave *i2c)
{
LM823KbdState *s = FROM_I2C_SLAVE(LM823KbdState, i2c);
@@ -494,19 +494,28 @@ void lm832x_key_event(DeviceState *dev, int key, int state)
lm_kbd_irq_update(s);
}
-static I2CSlaveInfo lm8323_info = {
- .qdev.name = "lm8323",
- .qdev.size = sizeof(LM823KbdState),
- .qdev.vmsd = &vmstate_lm_kbd,
- .init = lm8323_init,
- .event = lm_i2c_event,
- .recv = lm_i2c_rx,
- .send = lm_i2c_tx
+static void lm8323_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = lm8323_init;
+ k->event = lm_i2c_event;
+ k->recv = lm_i2c_rx;
+ k->send = lm_i2c_tx;
+ dc->vmsd = &vmstate_lm_kbd;
+}
+
+static TypeInfo lm8323_info = {
+ .name = "lm8323",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(LM823KbdState),
+ .class_init = lm8323_class_init,
};
static void lm832x_register_devices(void)
{
- i2c_register_slave(&lm8323_info);
+ type_register_static(&lm8323_info);
}
device_init(lm832x_register_devices)
diff --git a/hw/loader.c b/hw/loader.c
index 446b62874e..415cdce534 100644
--- a/hw/loader.c
+++ b/hw/loader.c
@@ -108,8 +108,12 @@ int load_image_targphys(const char *filename,
int size;
size = get_image_size(filename);
- if (size > 0)
+ if (size > max_sz) {
+ return -1;
+ }
+ if (size > 0) {
rom_add_file_fixed(filename, addr, -1);
+ }
return size;
}
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 0d3a1016df..9a7ffe3f42 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1681,7 +1681,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
DeviceState *dev;
QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
- dev->info->reset(dev);
+ device_reset(dev);
}
s->sstat0 |= LSI_SSTAT0_RST;
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
@@ -2120,23 +2120,31 @@ static int lsi_scsi_init(PCIDevice *dev)
return 0;
}
-static PCIDeviceInfo lsi_info = {
- .qdev.name = "lsi53c895a",
- .qdev.alias = "lsi",
- .qdev.size = sizeof(LSIState),
- .qdev.reset = lsi_scsi_reset,
- .qdev.vmsd = &vmstate_lsi_scsi,
- .init = lsi_scsi_init,
- .exit = lsi_scsi_uninit,
- .vendor_id = PCI_VENDOR_ID_LSI_LOGIC,
- .device_id = PCI_DEVICE_ID_LSI_53C895A,
- .class_id = PCI_CLASS_STORAGE_SCSI,
- .subsystem_id = 0x1000,
+static void lsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = lsi_scsi_init;
+ k->exit = lsi_scsi_uninit;
+ k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
+ k->device_id = PCI_DEVICE_ID_LSI_53C895A;
+ k->class_id = PCI_CLASS_STORAGE_SCSI;
+ k->subsystem_id = 0x1000;
+ dc->reset = lsi_scsi_reset;
+ dc->vmsd = &vmstate_lsi_scsi;
+}
+
+static TypeInfo lsi_info = {
+ .name = "lsi53c895a",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(LSIState),
+ .class_init = lsi_class_init,
};
static void lsi53c895a_register_devices(void)
{
- pci_qdev_register(&lsi_info);
+ type_register_static(&lsi_info);
}
device_init(lsi53c895a_register_devices);
diff --git a/hw/m48t59.c b/hw/m48t59.c
index c0439966cf..c35867d0a1 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -126,7 +126,7 @@ static void alarm_cb (void *opaque)
/* Repeat once a second */
next_time = 1;
}
- qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(vm_clock) +
+ qemu_mod_timer(NVRAM->alrm_timer, qemu_get_clock_ns(rtc_clock) +
next_time * 1000);
qemu_set_irq(NVRAM->IRQ, 0);
}
@@ -687,7 +687,7 @@ static void m48t59_init_common(M48t59State *s)
{
s->buffer = g_malloc0(s->size);
if (s->type == 59) {
- s->alrm_timer = qemu_new_timer_ns(vm_clock, &alarm_cb, s);
+ s->alrm_timer = qemu_new_timer_ns(rtc_clock, &alarm_cb, s);
s->wd_timer = qemu_new_timer_ns(vm_clock, &watchdog_cb, s);
}
qemu_get_timedate(&s->alarm, 0);
@@ -720,37 +720,58 @@ static int m48t59_init1(SysBusDevice *dev)
return 0;
}
-static ISADeviceInfo m48t59_isa_info = {
- .init = m48t59_init_isa1,
- .qdev.name = "m48t59_isa",
- .qdev.size = sizeof(M48t59ISAState),
- .qdev.reset = m48t59_reset_isa,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1),
- DEFINE_PROP_UINT32("type", M48t59ISAState, state.type, -1),
- DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property m48t59_isa_properties[] = {
+ DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1),
+ DEFINE_PROP_UINT32("type", M48t59ISAState, state.type, -1),
+ DEFINE_PROP_HEX32( "io_base", M48t59ISAState, state.io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo m48t59_info = {
- .init = m48t59_init1,
- .qdev.name = "m48t59",
- .qdev.size = sizeof(M48t59SysBusState),
- .qdev.reset = m48t59_reset_sysbus,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1),
- DEFINE_PROP_UINT32("type", M48t59SysBusState, state.type, -1),
- DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void m48t59_init_class_isa1(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = m48t59_init_isa1;
+ dc->no_user = 1;
+ dc->reset = m48t59_reset_isa;
+ dc->props = m48t59_isa_properties;
+}
+
+static TypeInfo m48t59_isa_info = {
+ .name = "m48t59_isa",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(M48t59ISAState),
+ .class_init = m48t59_init_class_isa1,
+};
+
+static Property m48t59_properties[] = {
+ DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1),
+ DEFINE_PROP_UINT32("type", M48t59SysBusState, state.type, -1),
+ DEFINE_PROP_HEX32( "io_base", M48t59SysBusState, state.io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void m48t59_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = m48t59_init1;
+ dc->reset = m48t59_reset_sysbus;
+ dc->props = m48t59_properties;
+}
+
+static TypeInfo m48t59_info = {
+ .name = "m48t59",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(M48t59SysBusState),
+ .class_init = m48t59_class_init,
};
static void m48t59_register_devices(void)
{
- sysbus_register_withprop(&m48t59_info);
- isa_qdev_register(&m48t59_isa_info);
+ type_register_static(&m48t59_info);
+ type_register_static(&m48t59_isa_info);
}
device_init(m48t59_register_devices)
diff --git a/hw/macio.c b/hw/macio.c
index cc6ae40050..3d648e934b 100644
--- a/hw/macio.c
+++ b/hw/macio.c
@@ -27,8 +27,9 @@
#include "pci.h"
#include "escc.h"
-typedef struct macio_state_t macio_state_t;
-struct macio_state_t {
+typedef struct MacIOState
+{
+ PCIDevice parent;
int is_oldworld;
MemoryRegion bar;
MemoryRegion *pic_mem;
@@ -38,9 +39,9 @@ struct macio_state_t {
void *nvram;
int nb_ide;
MemoryRegion *ide_mem[4];
-};
+} MacIOState;
-static void macio_bar_setup(macio_state_t *macio_state)
+static void macio_bar_setup(MacIOState *macio_state)
{
int i;
MemoryRegion *bar = &macio_state->bar;
@@ -74,6 +75,35 @@ static void macio_bar_setup(macio_state_t *macio_state)
macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000);
}
+static int macio_initfn(PCIDevice *d)
+{
+ d->config[0x3d] = 0x01; // interrupt on pin 1
+ return 0;
+}
+
+static void macio_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = macio_initfn;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->class_id = PCI_CLASS_OTHERS << 8;
+}
+
+static TypeInfo macio_info = {
+ .name = "macio",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(MacIOState),
+ .class_init = macio_class_init,
+};
+
+static void macio_register(void)
+{
+ type_register_static(&macio_info);
+}
+
+device_init(macio_register);
+
void macio_init (PCIBus *bus, int device_id, int is_oldworld,
MemoryRegion *pic_mem, MemoryRegion *dbdma_mem,
MemoryRegion *cuda_mem, void *nvram,
@@ -81,13 +111,12 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld,
MemoryRegion *escc_mem)
{
PCIDevice *d;
- macio_state_t *macio_state;
+ MacIOState *macio_state;
int i;
- d = pci_register_device(bus, "macio",
- sizeof(PCIDevice) + sizeof(macio_state_t),
- -1, NULL, NULL);
- macio_state = (macio_state_t *)(d + 1);
+ d = pci_create_simple(bus, -1, "macio");
+
+ macio_state = DO_UPCAST(MacIOState, parent, d);
macio_state->is_oldworld = is_oldworld;
macio_state->pic_mem = pic_mem;
macio_state->dbdma_mem = dbdma_mem;
@@ -104,11 +133,7 @@ void macio_init (PCIBus *bus, int device_id, int is_oldworld,
/* Note: this code is strongly inspirated from the corresponding code
in PearPC */
- pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE);
pci_config_set_device_id(d->config, device_id);
- pci_config_set_class(d->config, PCI_CLASS_OTHERS << 8);
-
- d->config[0x3d] = 0x01; // interrupt on pin 1
macio_bar_setup(macio_state);
pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar);
diff --git a/hw/marvell_88w8618_audio.c b/hw/marvell_88w8618_audio.c
index 0cd8410622..b628f1718d 100644
--- a/hw/marvell_88w8618_audio.c
+++ b/hw/marvell_88w8618_audio.c
@@ -50,7 +50,7 @@ typedef struct mv88w8618_audio_state {
uint32_t play_pos;
uint32_t last_free;
uint32_t clock_div;
- DeviceState *wm;
+ void *wm;
} mv88w8618_audio_state;
static void mv88w8618_audio_callback(void *opaque, int free_out, int free_in)
@@ -272,25 +272,32 @@ static const VMStateDescription mv88w8618_audio_vmsd = {
}
};
-static SysBusDeviceInfo mv88w8618_audio_info = {
- .init = mv88w8618_audio_init,
- .qdev.name = "mv88w8618_audio",
- .qdev.size = sizeof(mv88w8618_audio_state),
- .qdev.reset = mv88w8618_audio_reset,
- .qdev.vmsd = &mv88w8618_audio_vmsd,
- .qdev.props = (Property[]) {
- {
- .name = "wm8750",
- .info = &qdev_prop_ptr,
- .offset = offsetof(mv88w8618_audio_state, wm),
- },
- {/* end of list */}
- }
+static Property mv88w8618_audio_properties[] = {
+ DEFINE_PROP_PTR("wm8750", mv88w8618_audio_state, wm),
+ {/* end of list */},
+};
+
+static void mv88w8618_audio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_audio_init;
+ dc->reset = mv88w8618_audio_reset;
+ dc->vmsd = &mv88w8618_audio_vmsd;
+ dc->props = mv88w8618_audio_properties;
+}
+
+static TypeInfo mv88w8618_audio_info = {
+ .name = "mv88w8618_audio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_audio_state),
+ .class_init = mv88w8618_audio_class_init,
};
static void mv88w8618_register_devices(void)
{
- sysbus_register_withprop(&mv88w8618_audio_info);
+ type_register_static(&mv88w8618_audio_info);
}
device_init(mv88w8618_register_devices)
diff --git a/hw/max111x.c b/hw/max111x.c
index fc79814bf8..9d61aa98db 100644
--- a/hw/max111x.c
+++ b/hw/max111x.c
@@ -153,24 +153,40 @@ void max111x_set_input(DeviceState *dev, int line, uint8_t value)
s->input[line] = value;
}
-static SSISlaveInfo max1110_info = {
- .qdev.name = "max1110",
- .qdev.size = sizeof(MAX111xState),
- .init = max1110_init,
- .transfer = max111x_transfer
+static void max1110_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = max1110_init;
+ k->transfer = max111x_transfer;
+}
+
+static TypeInfo max1110_info = {
+ .name = "max1110",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(MAX111xState),
+ .class_init = max1110_class_init,
};
-static SSISlaveInfo max1111_info = {
- .qdev.name = "max1111",
- .qdev.size = sizeof(MAX111xState),
- .init = max1111_init,
- .transfer = max111x_transfer
+static void max1111_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = max1111_init;
+ k->transfer = max111x_transfer;
+}
+
+static TypeInfo max1111_info = {
+ .name = "max1111",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(MAX111xState),
+ .class_init = max1111_class_init,
};
static void max111x_register_devices(void)
{
- ssi_register_slave(&max1110_info);
- ssi_register_slave(&max1111_info);
+ type_register_static(&max1110_info);
+ type_register_static(&max1111_info);
}
device_init(max111x_register_devices)
diff --git a/hw/max7310.c b/hw/max7310.c
index c1bdb2ee0c..3a6bb961ef 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -10,7 +10,7 @@
#include "i2c.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int i2c_command_byte;
int len;
@@ -33,7 +33,7 @@ static void max7310_reset(DeviceState *dev)
s->command = 0x00;
}
-static int max7310_rx(i2c_slave *i2c)
+static int max7310_rx(I2CSlave *i2c)
{
MAX7310State *s = (MAX7310State *) i2c;
@@ -68,7 +68,7 @@ static int max7310_rx(i2c_slave *i2c)
return 0xff;
}
-static int max7310_tx(i2c_slave *i2c, uint8_t data)
+static int max7310_tx(I2CSlave *i2c, uint8_t data)
{
MAX7310State *s = (MAX7310State *) i2c;
uint8_t diff;
@@ -123,7 +123,7 @@ static int max7310_tx(i2c_slave *i2c, uint8_t data)
return 0;
}
-static void max7310_event(i2c_slave *i2c, enum i2c_event event)
+static void max7310_event(I2CSlave *i2c, enum i2c_event event)
{
MAX7310State *s = (MAX7310State *) i2c;
s->len = 0;
@@ -175,7 +175,7 @@ static void max7310_gpio_set(void *opaque, int line, int level)
/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
* but also accepts sequences that are not SMBus so return an I2C device. */
-static int max7310_init(i2c_slave *i2c)
+static int max7310_init(I2CSlave *i2c)
{
MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c);
@@ -185,20 +185,29 @@ static int max7310_init(i2c_slave *i2c)
return 0;
}
-static I2CSlaveInfo max7310_info = {
- .qdev.name = "max7310",
- .qdev.size = sizeof(MAX7310State),
- .qdev.vmsd = &vmstate_max7310,
- .qdev.reset = max7310_reset,
- .init = max7310_init,
- .event = max7310_event,
- .recv = max7310_rx,
- .send = max7310_tx
+static void max7310_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = max7310_init;
+ k->event = max7310_event;
+ k->recv = max7310_rx;
+ k->send = max7310_tx;
+ dc->reset = max7310_reset;
+ dc->vmsd = &vmstate_max7310;
+}
+
+static TypeInfo max7310_info = {
+ .name = "max7310",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(MAX7310State),
+ .class_init = max7310_class_init,
};
static void max7310_register_devices(void)
{
- i2c_register_slave(&max7310_info);
+ type_register_static(&max7310_info);
}
device_init(max7310_register_devices)
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 657fa10d6d..4a43225707 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -101,6 +101,7 @@ typedef struct RTCState {
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
Notifier clock_reset_notifier;
+ LostTickPolicy lost_tick_policy;
} RTCState;
static void rtc_set_time(RTCState *s);
@@ -183,7 +184,7 @@ static void rtc_periodic_timer(void *opaque)
if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
#ifdef TARGET_I386
- if(rtc_td_hack) {
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
s->irq_reinject_on_ack_count = 0;
apic_reset_irq_delivered();
@@ -544,7 +545,7 @@ static int rtc_post_load(void *opaque, int version_id)
RTCState *s = opaque;
if (version_id >= 2) {
- if (rtc_td_hack) {
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
rtc_coalesced_timer_update(s);
}
}
@@ -589,7 +590,7 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data)
qemu_mod_timer(s->second_timer2, s->next_second_time);
rtc_timer_update(s, now);
#ifdef TARGET_I386
- if (rtc_td_hack) {
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
rtc_coalesced_timer_update(s);
}
#endif
@@ -605,8 +606,9 @@ static void rtc_reset(void *opaque)
qemu_irq_lower(s->irq);
#ifdef TARGET_I386
- if (rtc_td_hack)
- s->irq_coalesced = 0;
+ if (s->lost_tick_policy == LOST_TICK_SLEW) {
+ s->irq_coalesced = 0;
+ }
#endif
}
@@ -626,10 +628,10 @@ static void visit_type_int32(Visitor *v, int *value, const char *name, Error **e
visit_type_int(v, &val, name, errp);
}
-static void rtc_get_date(DeviceState *dev, Visitor *v, void *opaque,
+static void rtc_get_date(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
- ISADevice *isa = DO_UPCAST(ISADevice, qdev, dev);
+ ISADevice *isa = ISA_DEVICE(obj);
RTCState *s = DO_UPCAST(RTCState, dev, isa);
visit_start_struct(v, NULL, "struct tm", name, 0, errp);
@@ -654,12 +656,20 @@ static int rtc_initfn(ISADevice *dev)
rtc_set_date_from_host(dev);
- s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
#ifdef TARGET_I386
- if (rtc_td_hack)
+ switch (s->lost_tick_policy) {
+ case LOST_TICK_SLEW:
s->coalesced_timer =
qemu_new_timer_ns(rtc_clock, rtc_coalesced_timer, s);
+ break;
+ case LOST_TICK_DISCARD:
+ break;
+ default:
+ return -EINVAL;
+ }
#endif
+
+ s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
s->second_timer = qemu_new_timer_ns(rtc_clock, rtc_update_second, s);
s->second_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_second2, s);
@@ -676,8 +686,8 @@ static int rtc_initfn(ISADevice *dev)
qdev_set_legacy_instance_id(&dev->qdev, base, 2);
qemu_register_reset(rtc_reset, s);
- qdev_property_add(&s->dev.qdev, "date", "struct tm",
- rtc_get_date, NULL, NULL, s, NULL);
+ object_property_add(OBJECT(s), "date", "struct tm",
+ rtc_get_date, NULL, NULL, s, NULL);
return 0;
}
@@ -699,20 +709,32 @@ ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq)
return dev;
}
-static ISADeviceInfo mc146818rtc_info = {
- .qdev.name = "mc146818rtc",
- .qdev.size = sizeof(RTCState),
- .qdev.no_user = 1,
- .qdev.vmsd = &vmstate_rtc,
- .init = rtc_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property mc146818rtc_properties[] = {
+ DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
+ DEFINE_PROP_LOSTTICKPOLICY("lost_tick_policy", RTCState,
+ lost_tick_policy, LOST_TICK_DISCARD),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtc_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = rtc_initfn;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_rtc;
+ dc->props = mc146818rtc_properties;
+}
+
+static TypeInfo mc146818rtc_info = {
+ .name = "mc146818rtc",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(RTCState),
+ .class_init = rtc_class_initfn,
};
static void mc146818rtc_register(void)
{
- isa_qdev_register(&mc146818rtc_info);
+ type_register_static(&mc146818rtc_info);
}
device_init(mc146818rtc_register)
diff --git a/hw/milkymist-ac97.c b/hw/milkymist-ac97.c
index e824a49e9a..0881643a4c 100644
--- a/hw/milkymist-ac97.c
+++ b/hw/milkymist-ac97.c
@@ -319,17 +319,26 @@ static const VMStateDescription vmstate_milkymist_ac97 = {
}
};
-static SysBusDeviceInfo milkymist_ac97_info = {
- .init = milkymist_ac97_init,
- .qdev.name = "milkymist-ac97",
- .qdev.size = sizeof(MilkymistAC97State),
- .qdev.vmsd = &vmstate_milkymist_ac97,
- .qdev.reset = milkymist_ac97_reset,
+static void milkymist_ac97_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_ac97_init;
+ dc->reset = milkymist_ac97_reset;
+ dc->vmsd = &vmstate_milkymist_ac97;
+}
+
+static TypeInfo milkymist_ac97_info = {
+ .name = "milkymist-ac97",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistAC97State),
+ .class_init = milkymist_ac97_class_init,
};
static void milkymist_ac97_register(void)
{
- sysbus_register_withprop(&milkymist_ac97_info);
+ type_register_static(&milkymist_ac97_info);
}
device_init(milkymist_ac97_register)
diff --git a/hw/milkymist-hpdmc.c b/hw/milkymist-hpdmc.c
index be575c98a0..b5122afd57 100644
--- a/hw/milkymist-hpdmc.c
+++ b/hw/milkymist-hpdmc.c
@@ -145,17 +145,26 @@ static const VMStateDescription vmstate_milkymist_hpdmc = {
}
};
-static SysBusDeviceInfo milkymist_hpdmc_info = {
- .init = milkymist_hpdmc_init,
- .qdev.name = "milkymist-hpdmc",
- .qdev.size = sizeof(MilkymistHpdmcState),
- .qdev.vmsd = &vmstate_milkymist_hpdmc,
- .qdev.reset = milkymist_hpdmc_reset,
+static void milkymist_hpdmc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_hpdmc_init;
+ dc->reset = milkymist_hpdmc_reset;
+ dc->vmsd = &vmstate_milkymist_hpdmc;
+}
+
+static TypeInfo milkymist_hpdmc_info = {
+ .name = "milkymist-hpdmc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistHpdmcState),
+ .class_init = milkymist_hpdmc_class_init,
};
static void milkymist_hpdmc_register(void)
{
- sysbus_register_withprop(&milkymist_hpdmc_info);
+ type_register_static(&milkymist_hpdmc_info);
}
device_init(milkymist_hpdmc_register)
diff --git a/hw/milkymist-memcard.c b/hw/milkymist-memcard.c
index 865a46c127..3c1c68a2e7 100644
--- a/hw/milkymist-memcard.c
+++ b/hw/milkymist-memcard.c
@@ -278,17 +278,26 @@ static const VMStateDescription vmstate_milkymist_memcard = {
}
};
-static SysBusDeviceInfo milkymist_memcard_info = {
- .init = milkymist_memcard_init,
- .qdev.name = "milkymist-memcard",
- .qdev.size = sizeof(MilkymistMemcardState),
- .qdev.vmsd = &vmstate_milkymist_memcard,
- .qdev.reset = milkymist_memcard_reset,
+static void milkymist_memcard_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_memcard_init;
+ dc->reset = milkymist_memcard_reset;
+ dc->vmsd = &vmstate_milkymist_memcard;
+}
+
+static TypeInfo milkymist_memcard_info = {
+ .name = "milkymist-memcard",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistMemcardState),
+ .class_init = milkymist_memcard_class_init,
};
static void milkymist_memcard_register(void)
{
- sysbus_register_withprop(&milkymist_memcard_info);
+ type_register_static(&milkymist_memcard_info);
}
device_init(milkymist_memcard_register)
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
index 7006d29788..b9b553fc95 100644
--- a/hw/milkymist-minimac2.c
+++ b/hw/milkymist-minimac2.c
@@ -479,7 +479,7 @@ static int milkymist_minimac2_init(SysBusDevice *dev)
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0;
@@ -516,24 +516,35 @@ static const VMStateDescription vmstate_milkymist_minimac2 = {
}
};
-static SysBusDeviceInfo milkymist_minimac2_info = {
- .init = milkymist_minimac2_init,
- .qdev.name = "milkymist-minimac2",
- .qdev.size = sizeof(MilkymistMinimac2State),
- .qdev.vmsd = &vmstate_milkymist_minimac2,
- .qdev.reset = milkymist_minimac2_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
- buffers_base, 0),
- DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
- DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_minimac2_properties[] = {
+ DEFINE_PROP_TADDR("buffers_base", MilkymistMinimac2State,
+ buffers_base, 0),
+ DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
+ DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_minimac2_init;
+ dc->reset = milkymist_minimac2_reset;
+ dc->vmsd = &vmstate_milkymist_minimac2;
+ dc->props = milkymist_minimac2_properties;
+}
+
+static TypeInfo milkymist_minimac2_info = {
+ .name = "milkymist-minimac2",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistMinimac2State),
+ .class_init = milkymist_minimac2_class_init,
};
static void milkymist_minimac2_register(void)
{
- sysbus_register_withprop(&milkymist_minimac2_info);
+ type_register_static(&milkymist_minimac2_info);
}
device_init(milkymist_minimac2_register)
diff --git a/hw/milkymist-pfpu.c b/hw/milkymist-pfpu.c
index dc92eb68e3..1b73a4686b 100644
--- a/hw/milkymist-pfpu.c
+++ b/hw/milkymist-pfpu.c
@@ -519,17 +519,26 @@ static const VMStateDescription vmstate_milkymist_pfpu = {
}
};
-static SysBusDeviceInfo milkymist_pfpu_info = {
- .init = milkymist_pfpu_init,
- .qdev.name = "milkymist-pfpu",
- .qdev.size = sizeof(MilkymistPFPUState),
- .qdev.vmsd = &vmstate_milkymist_pfpu,
- .qdev.reset = milkymist_pfpu_reset,
+static void milkymist_pfpu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_pfpu_init;
+ dc->reset = milkymist_pfpu_reset;
+ dc->vmsd = &vmstate_milkymist_pfpu;
+}
+
+static TypeInfo milkymist_pfpu_info = {
+ .name = "milkymist-pfpu",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistPFPUState),
+ .class_init = milkymist_pfpu_class_init,
};
static void milkymist_pfpu_register(void)
{
- sysbus_register_withprop(&milkymist_pfpu_info);
+ type_register_static(&milkymist_pfpu_info);
}
device_init(milkymist_pfpu_register)
diff --git a/hw/milkymist-softusb.c b/hw/milkymist-softusb.c
index 83bd1c4c6b..5d496cbdb0 100644
--- a/hw/milkymist-softusb.c
+++ b/hw/milkymist-softusb.c
@@ -297,32 +297,35 @@ static const VMStateDescription vmstate_milkymist_softusb = {
}
};
-static SysBusDeviceInfo milkymist_softusb_info = {
- .init = milkymist_softusb_init,
- .qdev.name = "milkymist-softusb",
- .qdev.size = sizeof(MilkymistSoftUsbState),
- .qdev.vmsd = &vmstate_milkymist_softusb,
- .qdev.reset = milkymist_softusb_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32(
- "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
- ),
- DEFINE_PROP_UINT32(
- "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
- ),
- DEFINE_PROP_UINT32(
- "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
- ),
- DEFINE_PROP_UINT32(
- "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
- ),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_softusb_properties[] = {
+ DEFINE_PROP_UINT32("pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000),
+ DEFINE_PROP_UINT32("pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000),
+ DEFINE_PROP_UINT32("dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000),
+ DEFINE_PROP_UINT32("dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_softusb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_softusb_init;
+ dc->reset = milkymist_softusb_reset;
+ dc->vmsd = &vmstate_milkymist_softusb;
+ dc->props = milkymist_softusb_properties;
+}
+
+static TypeInfo milkymist_softusb_info = {
+ .name = "milkymist-softusb",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistSoftUsbState),
+ .class_init = milkymist_softusb_class_init,
};
static void milkymist_softusb_register(void)
{
- sysbus_register_withprop(&milkymist_softusb_info);
+ type_register_static(&milkymist_softusb_info);
}
device_init(milkymist_softusb_register)
diff --git a/hw/milkymist-sysctl.c b/hw/milkymist-sysctl.c
index bd2a298d2e..18171f6165 100644
--- a/hw/milkymist-sysctl.c
+++ b/hw/milkymist-sysctl.c
@@ -292,28 +292,39 @@ static const VMStateDescription vmstate_milkymist_sysctl = {
}
};
-static SysBusDeviceInfo milkymist_sysctl_info = {
- .init = milkymist_sysctl_init,
- .qdev.name = "milkymist-sysctl",
- .qdev.size = sizeof(MilkymistSysctlState),
- .qdev.vmsd = &vmstate_milkymist_sysctl,
- .qdev.reset = milkymist_sysctl_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
- freq_hz, 80000000),
- DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
- capabilities, 0x00000000),
- DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
- systemid, 0x10014d31),
- DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
- strappings, 0x00000001),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_sysctl_properties[] = {
+ DEFINE_PROP_UINT32("frequency", MilkymistSysctlState,
+ freq_hz, 80000000),
+ DEFINE_PROP_UINT32("capabilities", MilkymistSysctlState,
+ capabilities, 0x00000000),
+ DEFINE_PROP_UINT32("systemid", MilkymistSysctlState,
+ systemid, 0x10014d31),
+ DEFINE_PROP_UINT32("gpio_strappings", MilkymistSysctlState,
+ strappings, 0x00000001),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_sysctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_sysctl_init;
+ dc->reset = milkymist_sysctl_reset;
+ dc->vmsd = &vmstate_milkymist_sysctl;
+ dc->props = milkymist_sysctl_properties;
+}
+
+static TypeInfo milkymist_sysctl_info = {
+ .name = "milkymist-sysctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistSysctlState),
+ .class_init = milkymist_sysctl_class_init,
};
static void milkymist_sysctl_register(void)
{
- sysbus_register_withprop(&milkymist_sysctl_info);
+ type_register_static(&milkymist_sysctl_info);
}
device_init(milkymist_sysctl_register)
diff --git a/hw/milkymist-tmu2.c b/hw/milkymist-tmu2.c
index 20110e5a83..474eae0a4a 100644
--- a/hw/milkymist-tmu2.c
+++ b/hw/milkymist-tmu2.c
@@ -465,17 +465,26 @@ static const VMStateDescription vmstate_milkymist_tmu2 = {
}
};
-static SysBusDeviceInfo milkymist_tmu2_info = {
- .init = milkymist_tmu2_init,
- .qdev.name = "milkymist-tmu2",
- .qdev.size = sizeof(MilkymistTMU2State),
- .qdev.vmsd = &vmstate_milkymist_tmu2,
- .qdev.reset = milkymist_tmu2_reset,
+static void milkymist_tmu2_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_tmu2_init;
+ dc->reset = milkymist_tmu2_reset;
+ dc->vmsd = &vmstate_milkymist_tmu2;
+}
+
+static TypeInfo milkymist_tmu2_info = {
+ .name = "milkymist-tmu2",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistTMU2State),
+ .class_init = milkymist_tmu2_class_init,
};
static void milkymist_tmu2_register(void)
{
- sysbus_register_withprop(&milkymist_tmu2_info);
+ type_register_static(&milkymist_tmu2_info);
}
device_init(milkymist_tmu2_register)
diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c
index eaf1c0dce1..f9a229cf68 100644
--- a/hw/milkymist-uart.c
+++ b/hw/milkymist-uart.c
@@ -199,7 +199,7 @@ static int milkymist_uart_init(SysBusDevice *dev)
"milkymist-uart", R_MAX * 4);
sysbus_init_mmio(dev, &s->regs_region);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr) {
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
}
@@ -218,17 +218,26 @@ static const VMStateDescription vmstate_milkymist_uart = {
}
};
-static SysBusDeviceInfo milkymist_uart_info = {
- .init = milkymist_uart_init,
- .qdev.name = "milkymist-uart",
- .qdev.size = sizeof(MilkymistUartState),
- .qdev.vmsd = &vmstate_milkymist_uart,
- .qdev.reset = milkymist_uart_reset,
+static void milkymist_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_uart_init;
+ dc->reset = milkymist_uart_reset;
+ dc->vmsd = &vmstate_milkymist_uart;
+}
+
+static TypeInfo milkymist_uart_info = {
+ .name = "milkymist-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistUartState),
+ .class_init = milkymist_uart_class_init,
};
static void milkymist_uart_register(void)
{
- sysbus_register_withprop(&milkymist_uart_info);
+ type_register_static(&milkymist_uart_info);
}
device_init(milkymist_uart_register)
diff --git a/hw/milkymist-vgafb.c b/hw/milkymist-vgafb.c
index 108115e300..92ad02f9e2 100644
--- a/hw/milkymist-vgafb.c
+++ b/hw/milkymist-vgafb.c
@@ -299,22 +299,33 @@ static const VMStateDescription vmstate_milkymist_vgafb = {
}
};
-static SysBusDeviceInfo milkymist_vgafb_info = {
- .init = milkymist_vgafb_init,
- .qdev.name = "milkymist-vgafb",
- .qdev.size = sizeof(MilkymistVgafbState),
- .qdev.vmsd = &vmstate_milkymist_vgafb,
- .qdev.reset = milkymist_vgafb_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
- DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property milkymist_vgafb_properties[] = {
+ DEFINE_PROP_UINT32("fb_offset", MilkymistVgafbState, fb_offset, 0x0),
+ DEFINE_PROP_UINT32("fb_mask", MilkymistVgafbState, fb_mask, 0xffffffff),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_vgafb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = milkymist_vgafb_init;
+ dc->reset = milkymist_vgafb_reset;
+ dc->vmsd = &vmstate_milkymist_vgafb;
+ dc->props = milkymist_vgafb_properties;
+}
+
+static TypeInfo milkymist_vgafb_info = {
+ .name = "milkymist-vgafb",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MilkymistVgafbState),
+ .class_init = milkymist_vgafb_class_init,
};
static void milkymist_vgafb_register(void)
{
- sysbus_register_withprop(&milkymist_vgafb_info);
+ type_register_static(&milkymist_vgafb_info);
}
device_init(milkymist_vgafb_register)
diff --git a/hw/milkymist-vgafb_template.h b/hw/milkymist-vgafb_template.h
index 69af9ef3f6..1d33ee8b50 100644
--- a/hw/milkymist-vgafb_template.h
+++ b/hw/milkymist-vgafb_template.h
@@ -39,7 +39,7 @@
#elif BITS == 24
#define COPY_PIXEL(to, r, g, b) \
do { \
- uint32 tmp = rgb_to_pixel24(r, g, b); \
+ uint32_t tmp = rgb_to_pixel24(r, g, b); \
*(to++) = tmp & 0xff; \
*(to++) = (tmp >> 8) & 0xff; \
*(to++) = (tmp >> 16) & 0xff; \
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index e625ec398f..d232630e66 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -996,11 +996,7 @@ void mips_malta_init (ram_addr_t ram_size,
if (cirrus_vga_enabled) {
pci_cirrus_vga_init(pci_bus);
} else if (vmsvga_enabled) {
- if (!pci_vmsvga_init(pci_bus)) {
- fprintf(stderr, "Warning: vmware_vga not available,"
- " using standard VGA instead\n");
- pci_vga_init(pci_bus);
- }
+ pci_vmsvga_init(pci_bus);
} else if (std_vga_enabled) {
pci_vga_init(pci_bus);
}
@@ -1011,13 +1007,18 @@ static int mips_malta_sysbus_device_init(SysBusDevice *sysbusdev)
return 0;
}
-static SysBusDeviceInfo mips_malta_device = {
- .init = mips_malta_sysbus_device_init,
- .qdev.name = "mips-malta",
- .qdev.size = sizeof(MaltaState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_END_OF_LIST(),
- }
+static void mips_malta_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mips_malta_sysbus_device_init;
+}
+
+static TypeInfo mips_malta_device = {
+ .name = "mips-malta",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MaltaState),
+ .class_init = mips_malta_class_init,
};
static QEMUMachine mips_malta_machine = {
@@ -1030,7 +1031,7 @@ static QEMUMachine mips_malta_machine = {
static void mips_malta_device_init(void)
{
- sysbus_register_withprop(&mips_malta_device);
+ type_register_static(&mips_malta_device);
}
static void mips_malta_machine_init(void)
diff --git a/hw/mipsnet.c b/hw/mipsnet.c
index b1234b8282..a0e6c9fa1e 100644
--- a/hw/mipsnet.c
+++ b/hw/mipsnet.c
@@ -240,7 +240,7 @@ static int mipsnet_sysbus_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0;
@@ -252,22 +252,33 @@ static void mipsnet_sysbus_reset(DeviceState *dev)
mipsnet_reset(s);
}
-static SysBusDeviceInfo mipsnet_info = {
- .init = mipsnet_sysbus_init,
- .qdev.name = "mipsnet",
- .qdev.desc = "MIPS Simulator network device",
- .qdev.size = sizeof(MIPSnetState),
- .qdev.vmsd = &vmstate_mipsnet,
- .qdev.reset = mipsnet_sysbus_reset,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property mipsnet_properties[] = {
+ DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mipsnet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mipsnet_sysbus_init;
+ dc->desc = "MIPS Simulator network device";
+ dc->reset = mipsnet_sysbus_reset;
+ dc->vmsd = &vmstate_mipsnet;
+ dc->props = mipsnet_properties;
+}
+
+static TypeInfo mipsnet_info = {
+ .name = "mipsnet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MIPSnetState),
+ .class_init = mipsnet_class_init,
};
static void mipsnet_register_devices(void)
{
- sysbus_register_withprop(&mipsnet_info);
+ type_register_static(&mipsnet_info);
}
device_init(mipsnet_register_devices)
diff --git a/hw/mpc8544_guts.c b/hw/mpc8544_guts.c
index f01b38cfc2..28cd60d89c 100644
--- a/hw/mpc8544_guts.c
+++ b/hw/mpc8544_guts.c
@@ -121,14 +121,22 @@ static int mpc8544_guts_initfn(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo mpc8544_guts_info = {
- .init = mpc8544_guts_initfn,
- .qdev.name = "mpc8544-guts",
- .qdev.size = sizeof(GutsState),
+static void mpc8544_guts_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mpc8544_guts_initfn;
+}
+
+static TypeInfo mpc8544_guts_info = {
+ .name = "mpc8544-guts",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(GutsState),
+ .class_init = mpc8544_guts_class_init,
};
static void mpc8544_guts_register(void)
{
- sysbus_register_withprop(&mpc8544_guts_info);
+ type_register_static(&mpc8544_guts_info);
}
device_init(mpc8544_guts_register);
diff --git a/hw/msi.c b/hw/msi.c
index f214fcf579..5d6ceb6df0 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -36,6 +36,9 @@
#define PCI_MSI_VECTORS_MAX 32
+/* Flag for interrupt controller to declare MSI/MSI-X support */
+bool msi_supported;
+
/* If we get rid of cap allocator, we won't need this. */
static inline uint8_t msi_cap_sizeof(uint16_t flags)
{
@@ -116,6 +119,11 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
uint16_t flags;
uint8_t cap_size;
int config_offset;
+
+ if (!msi_supported) {
+ return -ENOTSUP;
+ }
+
MSI_DEV_PRINTF(dev,
"init offset: 0x%"PRIx8" vector: %"PRId8
" 64bit %d mask %d\n",
diff --git a/hw/msi.h b/hw/msi.h
index 5766018d79..3040bb0b43 100644
--- a/hw/msi.h
+++ b/hw/msi.h
@@ -24,6 +24,8 @@
#include "qemu-common.h"
#include "pci.h"
+extern bool msi_supported;
+
bool msi_enabled(const PCIDevice *dev);
int msi_init(struct PCIDevice *dev, uint8_t offset,
unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
diff --git a/hw/msix.c b/hw/msix.c
index f47d26bb49..3835eaaf28 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -15,6 +15,7 @@
*/
#include "hw.h"
+#include "msi.h"
#include "msix.h"
#include "pci.h"
#include "range.h"
@@ -35,9 +36,6 @@
#define MSIX_MAX_ENTRIES 32
-/* Flag for interrupt controller to declare MSI-X support */
-int msix_supported;
-
/* Add MSI-X capability to the config space for the device. */
/* Given a bar and its size, add MSI-X table on top of it
* and fill MSI-X capability in the config space.
@@ -238,10 +236,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
unsigned bar_nr, unsigned bar_size)
{
int ret;
+
/* Nothing to do if MSI is not supported by interrupt controller */
- if (!msix_supported)
+ if (!msi_supported) {
return -ENOTSUP;
-
+ }
if (nentries > MSIX_MAX_ENTRIES)
return -EINVAL;
diff --git a/hw/msix.h b/hw/msix.h
index 7e04336618..5aba22b858 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -29,6 +29,4 @@ void msix_notify(PCIDevice *dev, unsigned vector);
void msix_reset(PCIDevice *dev);
-extern int msix_supported;
-
#endif
diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c
index 8bfa5dda37..1729db01a4 100644
--- a/hw/mst_fpga.c
+++ b/hw/mst_fpga.c
@@ -238,16 +238,25 @@ static VMStateDescription vmstate_mst_fpga_regs = {
},
};
-static SysBusDeviceInfo mst_fpga_info = {
- .init = mst_fpga_init,
- .qdev.name = "mainstone-fpga",
- .qdev.desc = "Mainstone II FPGA",
- .qdev.size = sizeof(mst_irq_state),
- .qdev.vmsd = &vmstate_mst_fpga_regs,
+static void mst_fpga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mst_fpga_init;
+ dc->desc = "Mainstone II FPGA";
+ dc->vmsd = &vmstate_mst_fpga_regs;
+}
+
+static TypeInfo mst_fpga_info = {
+ .name = "mainstone-fpga",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mst_irq_state),
+ .class_init = mst_fpga_class_init,
};
static void mst_fpga_register(void)
{
- sysbus_register_withprop(&mst_fpga_info);
+ type_register_static(&mst_fpga_info);
}
device_init(mst_fpga_register);
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 977ffb6e50..ac909248d4 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -387,7 +387,7 @@ static int mv88w8618_eth_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
s->nic = qemu_new_nic(&net_mv88w8618_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
memory_region_init_io(&s->iomem, &mv88w8618_eth_ops, s, "mv88w8618-eth",
MP_ETH_SIZE);
sysbus_init_mmio(dev, &s->iomem);
@@ -412,15 +412,26 @@ static const VMStateDescription mv88w8618_eth_vmsd = {
}
};
-static SysBusDeviceInfo mv88w8618_eth_info = {
- .init = mv88w8618_eth_init,
- .qdev.name = "mv88w8618_eth",
- .qdev.size = sizeof(mv88w8618_eth_state),
- .qdev.vmsd = &mv88w8618_eth_vmsd,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property mv88w8618_eth_properties[] = {
+ DEFINE_NIC_PROPERTIES(mv88w8618_eth_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void mv88w8618_eth_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_eth_init;
+ dc->vmsd = &mv88w8618_eth_vmsd;
+ dc->props = mv88w8618_eth_properties;
+}
+
+static TypeInfo mv88w8618_eth_info = {
+ .name = "mv88w8618_eth",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_eth_state),
+ .class_init = mv88w8618_eth_class_init,
};
/* LCD register offsets */
@@ -624,11 +635,20 @@ static const VMStateDescription musicpal_lcd_vmsd = {
}
};
-static SysBusDeviceInfo musicpal_lcd_info = {
- .init = musicpal_lcd_init,
- .qdev.name = "musicpal_lcd",
- .qdev.size = sizeof(musicpal_lcd_state),
- .qdev.vmsd = &musicpal_lcd_vmsd,
+static void musicpal_lcd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = musicpal_lcd_init;
+ dc->vmsd = &musicpal_lcd_vmsd;
+}
+
+static TypeInfo musicpal_lcd_info = {
+ .name = "musicpal_lcd",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(musicpal_lcd_state),
+ .class_init = musicpal_lcd_class_init,
};
/* PIC register offsets */
@@ -733,12 +753,21 @@ static const VMStateDescription mv88w8618_pic_vmsd = {
}
};
-static SysBusDeviceInfo mv88w8618_pic_info = {
- .init = mv88w8618_pic_init,
- .qdev.name = "mv88w8618_pic",
- .qdev.size = sizeof(mv88w8618_pic_state),
- .qdev.reset = mv88w8618_pic_reset,
- .qdev.vmsd = &mv88w8618_pic_vmsd,
+static void mv88w8618_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_pic_init;
+ dc->reset = mv88w8618_pic_reset;
+ dc->vmsd = &mv88w8618_pic_vmsd;
+}
+
+static TypeInfo mv88w8618_pic_info = {
+ .name = "mv88w8618_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_pic_state),
+ .class_init = mv88w8618_pic_class_init,
};
/* PIT register offsets */
@@ -901,12 +930,21 @@ static const VMStateDescription mv88w8618_pit_vmsd = {
}
};
-static SysBusDeviceInfo mv88w8618_pit_info = {
- .init = mv88w8618_pit_init,
- .qdev.name = "mv88w8618_pit",
- .qdev.size = sizeof(mv88w8618_pit_state),
- .qdev.reset = mv88w8618_pit_reset,
- .qdev.vmsd = &mv88w8618_pit_vmsd,
+static void mv88w8618_pit_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_pit_init;
+ dc->reset = mv88w8618_pit_reset;
+ dc->vmsd = &mv88w8618_pit_vmsd;
+}
+
+static TypeInfo mv88w8618_pit_info = {
+ .name = "mv88w8618_pit",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_pit_state),
+ .class_init = mv88w8618_pit_class_init,
};
/* Flash config register offsets */
@@ -973,11 +1011,20 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = {
}
};
-static SysBusDeviceInfo mv88w8618_flashcfg_info = {
- .init = mv88w8618_flashcfg_init,
- .qdev.name = "mv88w8618_flashcfg",
- .qdev.size = sizeof(mv88w8618_flashcfg_state),
- .qdev.vmsd = &mv88w8618_flashcfg_vmsd,
+static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = mv88w8618_flashcfg_init;
+ dc->vmsd = &mv88w8618_flashcfg_vmsd;
+}
+
+static TypeInfo mv88w8618_flashcfg_info = {
+ .name = "mv88w8618_flashcfg",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(mv88w8618_flashcfg_state),
+ .class_init = mv88w8618_flashcfg_class_init,
};
/* Misc register offsets */
@@ -1285,12 +1332,21 @@ static const VMStateDescription musicpal_gpio_vmsd = {
}
};
-static SysBusDeviceInfo musicpal_gpio_info = {
- .init = musicpal_gpio_init,
- .qdev.name = "musicpal_gpio",
- .qdev.size = sizeof(musicpal_gpio_state),
- .qdev.reset = musicpal_gpio_reset,
- .qdev.vmsd = &musicpal_gpio_vmsd,
+static void musicpal_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = musicpal_gpio_init;
+ dc->reset = musicpal_gpio_reset;
+ dc->vmsd = &musicpal_gpio_vmsd;
+}
+
+static TypeInfo musicpal_gpio_info = {
+ .name = "musicpal_gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(musicpal_gpio_state),
+ .class_init = musicpal_gpio_class_init,
};
/* Keyboard codes & masks */
@@ -1431,11 +1487,20 @@ static const VMStateDescription musicpal_key_vmsd = {
}
};
-static SysBusDeviceInfo musicpal_key_info = {
- .init = musicpal_key_init,
- .qdev.name = "musicpal_key",
- .qdev.size = sizeof(musicpal_key_state),
- .qdev.vmsd = &musicpal_key_vmsd,
+static void musicpal_key_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = musicpal_key_init;
+ dc->vmsd = &musicpal_key_vmsd;
+}
+
+static TypeInfo musicpal_key_info = {
+ .name = "musicpal_key",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(musicpal_key_state),
+ .class_init = musicpal_key_class_init,
};
static struct arm_boot_info musicpal_binfo = {
@@ -1602,17 +1667,30 @@ static void musicpal_machine_init(void)
machine_init(musicpal_machine_init);
+static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = mv88w8618_wlan_init;
+}
+
+static TypeInfo mv88w8618_wlan_info = {
+ .name = "mv88w8618_wlan",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = mv88w8618_wlan_class_init,
+};
+
static void musicpal_register_devices(void)
{
- sysbus_register_withprop(&mv88w8618_pic_info);
- sysbus_register_withprop(&mv88w8618_pit_info);
- sysbus_register_withprop(&mv88w8618_flashcfg_info);
- sysbus_register_withprop(&mv88w8618_eth_info);
- sysbus_register_dev("mv88w8618_wlan", sizeof(SysBusDevice),
- mv88w8618_wlan_init);
- sysbus_register_withprop(&musicpal_lcd_info);
- sysbus_register_withprop(&musicpal_gpio_info);
- sysbus_register_withprop(&musicpal_key_info);
+ type_register_static(&mv88w8618_pic_info);
+ type_register_static(&mv88w8618_pit_info);
+ type_register_static(&mv88w8618_flashcfg_info);
+ type_register_static(&mv88w8618_eth_info);
+ type_register_static(&mv88w8618_wlan_info);
+ type_register_static(&musicpal_lcd_info);
+ type_register_static(&musicpal_gpio_info);
+ type_register_static(&musicpal_key_info);
}
device_init(musicpal_register_devices)
diff --git a/hw/nand.c b/hw/nand.c
index 8597aa6b1c..5d947b1ced 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -417,23 +417,34 @@ static int nand_device_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo nand_info = {
- .init = nand_device_init,
- .qdev.name = "nand",
- .qdev.size = sizeof(NANDFlashState),
- .qdev.reset = nand_reset,
- .qdev.vmsd = &vmstate_nand,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
- DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
- DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property nand_properties[] = {
+ DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0),
+ DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0),
+ DEFINE_PROP_DRIVE("drive", NANDFlashState, bdrv),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void nand_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = nand_device_init;
+ dc->reset = nand_reset;
+ dc->vmsd = &vmstate_nand;
+ dc->props = nand_properties;
+}
+
+static TypeInfo nand_info = {
+ .name = "nand",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(NANDFlashState),
+ .class_init = nand_class_init,
};
static void nand_create_device(void)
{
- sysbus_register_withprop(&nand_info);
+ type_register_static(&nand_info);
}
/*
diff --git a/hw/ne2000-isa.c b/hw/ne2000-isa.c
index 11ffee7d7c..1352282152 100644
--- a/hw/ne2000-isa.c
+++ b/hw/ne2000-isa.c
@@ -76,27 +76,37 @@ static int isa_ne2000_initfn(ISADevice *dev)
ne2000_reset(s);
s->nic = qemu_new_nic(&net_ne2000_isa_info, &s->c,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
return 0;
}
-static ISADeviceInfo ne2000_isa_info = {
- .qdev.name = "ne2k_isa",
- .qdev.size = sizeof(ISANE2000State),
- .init = isa_ne2000_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
- DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9),
- DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property ne2000_isa_properties[] = {
+ DEFINE_PROP_HEX32("iobase", ISANE2000State, iobase, 0x300),
+ DEFINE_PROP_UINT32("irq", ISANE2000State, isairq, 9),
+ DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void isa_ne2000_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = isa_ne2000_initfn;
+ dc->props = ne2000_isa_properties;
+}
+
+static TypeInfo ne2000_isa_info = {
+ .name = "ne2k_isa",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISANE2000State),
+ .class_init = isa_ne2000_class_initfn,
};
static void ne2000_isa_register_devices(void)
{
- isa_qdev_register(&ne2000_isa_info);
+ type_register_static(&ne2000_isa_info);
}
device_init(ne2000_isa_register_devices)
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 62e082f8a9..080811ec4d 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -760,7 +760,7 @@ static int pci_ne2000_init(PCIDevice *pci_dev)
ne2000_reset(s);
s->nic = qemu_new_nic(&net_ne2000_info, &s->c,
- pci_dev->qdev.info->name, pci_dev->qdev.id, s);
+ object_get_typename(OBJECT(pci_dev)), pci_dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->c.macaddr.a);
if (!pci_dev->qdev.hotplugged) {
@@ -786,24 +786,35 @@ static int pci_ne2000_exit(PCIDevice *pci_dev)
return 0;
}
-static PCIDeviceInfo ne2000_info = {
- .qdev.name = "ne2k_pci",
- .qdev.size = sizeof(PCINE2000State),
- .qdev.vmsd = &vmstate_pci_ne2000,
- .init = pci_ne2000_init,
- .exit = pci_ne2000_exit,
- .vendor_id = PCI_VENDOR_ID_REALTEK,
- .device_id = PCI_DEVICE_ID_REALTEK_8029,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ne2000_properties[] = {
+ DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ne2000_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ne2000_init;
+ k->exit = pci_ne2000_exit;
+ k->vendor_id = PCI_VENDOR_ID_REALTEK;
+ k->device_id = PCI_DEVICE_ID_REALTEK_8029;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->vmsd = &vmstate_pci_ne2000;
+ dc->props = ne2000_properties;
+}
+
+static TypeInfo ne2000_info = {
+ .name = "ne2k_pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCINE2000State),
+ .class_init = ne2000_class_init,
};
static void ne2000_register_devices(void)
{
- pci_qdev_register(&ne2000_info);
+ type_register_static(&ne2000_info);
}
device_init(ne2000_register_devices)
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 29147be8b8..9a9a8e183f 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -731,40 +731,62 @@ static int omap2_gpio_init(SysBusDevice *dev)
* translation.)
*/
-static SysBusDeviceInfo omap_gpio_info = {
- .init = omap_gpio_init,
- .qdev.name = "omap-gpio",
- .qdev.size = sizeof(struct omap_gpif_s),
- .qdev.reset = omap_gpif_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property omap_gpio_properties[] = {
+ DEFINE_PROP_INT32("mpu_model", struct omap_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("clk", struct omap_gpif_s, clk),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo omap2_gpio_info = {
- .init = omap2_gpio_init,
- .qdev.name = "omap2-gpio",
- .qdev.size = sizeof(struct omap2_gpif_s),
- .qdev.reset = omap2_gpif_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
- DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
- DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
- DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
- DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
- DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
- DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
- DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
- DEFINE_PROP_END_OF_LIST()
- }
+static void omap_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap_gpio_init;
+ dc->reset = omap_gpif_reset;
+ dc->props = omap_gpio_properties;
+}
+
+static TypeInfo omap_gpio_info = {
+ .name = "omap-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_gpif_s),
+ .class_init = omap_gpio_class_init,
+};
+
+static Property omap2_gpio_properties[] = {
+ DEFINE_PROP_INT32("mpu_model", struct omap2_gpif_s, mpu_model, 0),
+ DEFINE_PROP_PTR("iclk", struct omap2_gpif_s, iclk),
+ DEFINE_PROP_PTR("fclk0", struct omap2_gpif_s, fclk[0]),
+ DEFINE_PROP_PTR("fclk1", struct omap2_gpif_s, fclk[1]),
+ DEFINE_PROP_PTR("fclk2", struct omap2_gpif_s, fclk[2]),
+ DEFINE_PROP_PTR("fclk3", struct omap2_gpif_s, fclk[3]),
+ DEFINE_PROP_PTR("fclk4", struct omap2_gpif_s, fclk[4]),
+ DEFINE_PROP_PTR("fclk5", struct omap2_gpif_s, fclk[5]),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap2_gpio_init;
+ dc->reset = omap2_gpif_reset;
+ dc->props = omap2_gpio_properties;
+}
+
+static TypeInfo omap2_gpio_info = {
+ .name = "omap2-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap2_gpif_s),
+ .class_init = omap2_gpio_class_init,
};
static void omap_gpio_register_device(void)
{
- sysbus_register_withprop(&omap_gpio_info);
- sysbus_register_withprop(&omap2_gpio_info);
+ type_register_static(&omap_gpio_info);
+ type_register_static(&omap2_gpio_info);
}
device_init(omap_gpio_register_device)
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index fc53ec71fb..5aa98a8fdb 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -373,16 +373,27 @@ static int omap_intc_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo omap_intc_info = {
- .init = omap_intc_init,
- .qdev.name = "omap-intc",
- .qdev.size = sizeof(struct omap_intr_handler_s),
- .qdev.reset = omap_inth_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
- DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property omap_intc_properties[] = {
+ DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100),
+ DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap_intc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap_intc_init;
+ dc->reset = omap_inth_reset;
+ dc->props = omap_intc_properties;
+}
+
+static TypeInfo omap_intc_info = {
+ .name = "omap-intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_intr_handler_s),
+ .class_init = omap_intc_class_init,
};
static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
@@ -604,24 +615,35 @@ static int omap2_intc_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo omap2_intc_info = {
- .init = omap2_intc_init,
- .qdev.name = "omap2-intc",
- .qdev.size = sizeof(struct omap_intr_handler_s),
- .qdev.reset = omap_inth_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
- revision, 0x21),
- DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
- DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property omap2_intc_properties[] = {
+ DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,
+ revision, 0x21),
+ DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk),
+ DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void omap2_intc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = omap2_intc_init;
+ dc->reset = omap_inth_reset;
+ dc->props = omap2_intc_properties;
+}
+
+static TypeInfo omap2_intc_info = {
+ .name = "omap2-intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct omap_intr_handler_s),
+ .class_init = omap2_intc_class_init,
};
static void omap_intc_register_device(void)
{
- sysbus_register_withprop(&omap_intc_info);
- sysbus_register_withprop(&omap2_intc_info);
+ type_register_static(&omap_intc_info);
+ type_register_static(&omap2_intc_info);
}
device_init(omap_intc_register_device)
diff --git a/hw/onenand.c b/hw/onenand.c
index 33c9718629..8744b04db3 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -802,24 +802,35 @@ static int onenand_initfn(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo onenand_info = {
- .init = onenand_initfn,
- .qdev.name = "onenand",
- .qdev.size = sizeof(OneNANDState),
- .qdev.reset = onenand_system_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
- DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
- DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
- DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
- DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
- DEFINE_PROP_END_OF_LIST()
- }
+static Property onenand_properties[] = {
+ DEFINE_PROP_UINT16("manufacturer_id", OneNANDState, id.man, 0),
+ DEFINE_PROP_UINT16("device_id", OneNANDState, id.dev, 0),
+ DEFINE_PROP_UINT16("version_id", OneNANDState, id.ver, 0),
+ DEFINE_PROP_INT32("shift", OneNANDState, shift, 0),
+ DEFINE_PROP_DRIVE("drive", OneNANDState, bdrv),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void onenand_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = onenand_initfn;
+ dc->reset = onenand_system_reset;
+ dc->props = onenand_properties;
+}
+
+static TypeInfo onenand_info = {
+ .name = "onenand",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OneNANDState),
+ .class_init = onenand_class_init,
};
static void onenand_register_device(void)
{
- sysbus_register_withprop(&onenand_info);
+ type_register_static(&onenand_info);
}
void *onenand_raw_otp(DeviceState *onenand_device)
diff --git a/hw/opencores_eth.c b/hw/opencores_eth.c
index f7cc1b403b..09f2757df3 100644
--- a/hw/opencores_eth.c
+++ b/hw/opencores_eth.c
@@ -717,7 +717,7 @@ static int sysbus_open_eth_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
s->nic = qemu_new_nic(&net_open_eth_info, &s->conf,
- s->dev.qdev.info->name, s->dev.qdev.id, s);
+ object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
return 0;
}
@@ -727,21 +727,32 @@ static void qdev_open_eth_reset(DeviceState *dev)
open_eth_reset(d);
}
-static SysBusDeviceInfo open_eth_info = {
- .qdev.name = "open_eth",
- .qdev.desc = "Opencores 10/100 Mbit Ethernet",
- .qdev.size = sizeof(OpenEthState),
- .qdev.reset = qdev_open_eth_reset,
- .init = sysbus_open_eth_init,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(OpenEthState, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property open_eth_properties[] = {
+ DEFINE_NIC_PROPERTIES(OpenEthState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void open_eth_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sysbus_open_eth_init;
+ dc->desc = "Opencores 10/100 Mbit Ethernet";
+ dc->reset = qdev_open_eth_reset;
+ dc->props = open_eth_properties;
+}
+
+static TypeInfo open_eth_info = {
+ .name = "open_eth",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OpenEthState),
+ .class_init = open_eth_class_init,
};
static void open_eth_register_devices(void)
{
- sysbus_register_withprop(&open_eth_info);
+ type_register_static(&open_eth_info);
}
device_init(open_eth_register_devices)
diff --git a/hw/openpic.c b/hw/openpic.c
index 22fc275b62..280b7a9bbb 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1181,41 +1181,17 @@ static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
}
-qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
+qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
qemu_irq **irqs, qemu_irq irq_out)
{
openpic_t *opp;
- uint8_t *pci_conf;
int i, m;
/* XXX: for now, only one CPU is supported */
if (nb_cpus != 1)
return NULL;
- if (bus) {
- opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
- -1, NULL, NULL);
- pci_conf = opp->pci_dev.config;
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
- pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
- pci_conf[0x3d] = 0x00; // no interrupt pin
-
- memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
-#if 0 // Don't implement ISU for now
- opp_io_memory = cpu_register_io_memory(openpic_src_read,
- openpic_src_write, NULL
- DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
- opp_io_memory);
-#endif
-
- /* Register I/O spaces */
- pci_register_bar(&opp->pci_dev, 0,
- PCI_BASE_ADDRESS_SPACE_MEMORY, &opp->mem);
- } else {
- opp = g_malloc0(sizeof(openpic_t));
- memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
- }
+ opp = g_malloc0(sizeof(openpic_t));
+ memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000);
// isu_base &= 0xFFFC0000;
opp->nb_cpus = nb_cpus;
diff --git a/hw/openpic.h b/hw/openpic.h
index 715f0847bf..855603026b 100644
--- a/hw/openpic.h
+++ b/hw/openpic.h
@@ -11,7 +11,7 @@ enum {
OPENPIC_OUTPUT_NB,
};
-qemu_irq *openpic_init (PCIBus *bus, MemoryRegion **pmem, int nb_cpus,
+qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus,
qemu_irq **irqs, qemu_irq irq_out);
qemu_irq *mpic_init (MemoryRegion *address_space, target_phys_addr_t base,
int nb_cpus, qemu_irq **irqs, qemu_irq irq_out);
diff --git a/hw/parallel.c b/hw/parallel.c
index c4c5dbee5b..484d727927 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -583,22 +583,32 @@ bool parallel_mm_init(MemoryRegion *address_space,
return true;
}
-static ISADeviceInfo parallel_isa_info = {
- .qdev.name = "isa-parallel",
- .qdev.size = sizeof(ISAParallelState),
- .init = parallel_isa_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("index", ISAParallelState, index, -1),
- DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase, -1),
- DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7),
- DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property parallel_isa_properties[] = {
+ DEFINE_PROP_UINT32("index", ISAParallelState, index, -1),
+ DEFINE_PROP_HEX32("iobase", ISAParallelState, iobase, -1),
+ DEFINE_PROP_UINT32("irq", ISAParallelState, isairq, 7),
+ DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void parallel_isa_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = parallel_isa_initfn;
+ dc->props = parallel_isa_properties;
+}
+
+static TypeInfo parallel_isa_info = {
+ .name = "isa-parallel",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAParallelState),
+ .class_init = parallel_isa_class_initfn,
};
static void parallel_register_devices(void)
{
- isa_qdev_register(&parallel_isa_info);
+ type_register_static(&parallel_isa_info);
}
device_init(parallel_register_devices)
diff --git a/hw/pc.c b/hw/pc.c
index 85304cf115..7f3aa65d20 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,9 +36,10 @@
#include "elf.h"
#include "multiboot.h"
#include "mc146818rtc.h"
-#include "msix.h"
+#include "msi.h"
#include "sysbus.h"
#include "sysemu.h"
+#include "kvm.h"
#include "blockdev.h"
#include "ui/qemu-spice.h"
#include "memory.h"
@@ -496,18 +497,26 @@ static int port92_initfn(ISADevice *dev)
return 0;
}
-static ISADeviceInfo port92_info = {
- .qdev.name = "port92",
- .qdev.size = sizeof(Port92State),
- .qdev.vmsd = &vmstate_port92_isa,
- .qdev.no_user = 1,
- .qdev.reset = port92_reset,
- .init = port92_initfn,
+static void port92_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = port92_initfn;
+ dc->no_user = 1;
+ dc->reset = port92_reset;
+ dc->vmsd = &vmstate_port92_isa;
+}
+
+static TypeInfo port92_info = {
+ .name = "port92",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(Port92State),
+ .class_init = port92_class_initfn,
};
static void port92_register(void)
{
- isa_qdev_register(&port92_info);
+ type_register_static(&port92_info);
}
device_init(port92_register)
@@ -609,7 +618,7 @@ static void *bochs_bios_init(void)
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
acpi_tables_len);
- fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
+ fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
smbios_table = smbios_get_table(&smbios_len);
if (smbios_table)
@@ -878,25 +887,30 @@ DeviceState *cpu_get_current_apic(void)
static DeviceState *apic_init(void *env, uint8_t apic_id)
{
DeviceState *dev;
- SysBusDevice *d;
static int apic_mapped;
- dev = qdev_create(NULL, "apic");
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ dev = qdev_create(NULL, "kvm-apic");
+ } else {
+ dev = qdev_create(NULL, "apic");
+ }
qdev_prop_set_uint8(dev, "id", apic_id);
qdev_prop_set_ptr(dev, "cpu_env", env);
qdev_init_nofail(dev);
- d = sysbus_from_qdev(dev);
/* XXX: mapping more APICs at the same memory location */
if (apic_mapped == 0) {
/* NOTE: the APIC is directly connected to the CPU - it is not
on the global memory bus. */
/* XXX: what if the base changes? */
- sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+ sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE);
apic_mapped = 1;
}
- msix_supported = 1;
+ /* KVM does not support MSI yet. */
+ if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+ msi_supported = true;
+ }
return dev;
}
@@ -1080,16 +1094,11 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus)
if (pci_bus) {
dev = pci_cirrus_vga_init(pci_bus);
} else {
- dev = isa_cirrus_vga_init(get_system_memory());
+ dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev;
}
} else if (vmsvga_enabled) {
if (pci_bus) {
dev = pci_vmsvga_init(pci_bus);
- if (!dev) {
- fprintf(stderr, "Warning: vmware_vga not available,"
- " using standard VGA instead\n");
- dev = pci_vga_init(pci_bus);
- }
} else {
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
}
diff --git a/hw/pc.h b/hw/pc.h
index 13e41f101e..c666ec9827 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -62,11 +62,11 @@ bool parallel_mm_init(MemoryRegion *address_space,
/* i8259.c */
-typedef struct PicState PicState;
-extern PicState *isa_pic;
+extern DeviceState *isa_pic;
qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
-int pic_read_irq(PicState *s);
-int pic_get_output(PicState *s);
+qemu_irq *kvm_i8259_init(ISABus *bus);
+int pic_read_irq(DeviceState *d);
+int pic_get_output(DeviceState *d);
void pic_info(Monitor *mon);
void irq_info(Monitor *mon);
@@ -226,7 +226,6 @@ int isa_vga_mm_init(target_phys_addr_t vram_base,
/* cirrus_vga.c */
DeviceState *pci_cirrus_vga_init(PCIBus *bus);
-DeviceState *isa_cirrus_vga_init(MemoryRegion *address_space);
/* ne2000.c */
static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd)
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 3aea3cc9de..c06f1b544e 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,7 +34,7 @@
#include "boards.h"
#include "ide.h"
#include "kvm.h"
-#include "kvmclock.h"
+#include "kvm/clock.h"
#include "sysemu.h"
#include "sysbus.h"
#include "arch_init.h"
@@ -53,13 +53,62 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+static void kvm_piix3_setup_irq_routing(bool pci_enabled)
+{
+#ifdef CONFIG_KVM
+ KVMState *s = kvm_state;
+ int ret, i;
+
+ if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+ for (i = 0; i < 8; ++i) {
+ if (i == 2) {
+ continue;
+ }
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
+ }
+ for (i = 8; i < 16; ++i) {
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
+ }
+ if (pci_enabled) {
+ for (i = 0; i < 24; ++i) {
+ if (i == 0) {
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
+ } else if (i != 2) {
+ kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i);
+ }
+ }
+ }
+ ret = kvm_irqchip_commit_routes(s);
+ if (ret < 0) {
+ hw_error("KVM IRQ routing setup failed");
+ }
+ }
+#endif /* CONFIG_KVM */
+}
+
+static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
+{
+ GSIState *s = opaque;
+
+ if (n < ISA_NUM_IRQS) {
+ /* Kernel will forward to both PIC and IOAPIC */
+ qemu_set_irq(s->i8259_irq[n], level);
+ } else {
+ qemu_set_irq(s->ioapic_irq[n], level);
+ }
+}
+
static void ioapic_init(GSIState *gsi_state)
{
DeviceState *dev;
SysBusDevice *d;
unsigned int i;
- dev = qdev_create(NULL, "ioapic");
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ dev = qdev_create(NULL, "kvm-ioapic");
+ } else {
+ dev = qdev_create(NULL, "ioapic");
+ }
qdev_init_nofail(dev);
d = sysbus_from_qdev(dev);
sysbus_mmio_map(d, 0, 0xfec00000);
@@ -134,7 +183,13 @@ static void pc_init1(MemoryRegion *system_memory,
}
gsi_state = g_malloc0(sizeof(*gsi_state));
- gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_piix3_setup_irq_routing(pci_enabled);
+ gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
+ GSI_NUM_PINS);
+ } else {
+ gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+ }
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
@@ -154,11 +209,13 @@ static void pc_init1(MemoryRegion *system_memory,
}
isa_bus_irqs(isa_bus, gsi);
- if (!xen_enabled()) {
+ if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+ i8259 = kvm_i8259_init(isa_bus);
+ } else if (xen_enabled()) {
+ i8259 = xen_interrupt_controller_init();
+ } else {
cpu_irq = pc_allocate_cpu_irq();
i8259 = i8259_init(isa_bus, cpu_irq[0]);
- } else {
- i8259 = xen_interrupt_controller_init();
}
for (i = 0; i < ISA_NUM_IRQS; i++) {
@@ -172,7 +229,7 @@ static void pc_init1(MemoryRegion *system_memory,
dev = pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL);
if (dev) {
- qdev_property_add_child(qdev_get_root(), "vga", dev, NULL);
+ object_property_add_child(object_get_root(), "vga", OBJECT(dev), NULL);
}
if (xen_enabled()) {
@@ -210,8 +267,8 @@ static void pc_init1(MemoryRegion *system_memory,
* For now, let's "fix" this by making judicious use of paths. This
* is not generally the right way to do this.
*/
- qdev_property_add_child(qdev_resolve_path("/i440fx/piix3", NULL),
- "rtc", (DeviceState *)rtc_state, NULL);
+ object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
+ "rtc", (Object *)rtc_state, NULL);
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
diff --git a/hw/pci.c b/hw/pci.c
index c3082bc7c6..5f4f80ed10 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -89,7 +89,6 @@ static const VMStateDescription vmstate_pcibus = {
VMSTATE_END_OF_LIST()
}
};
-
static int pci_bar(PCIDevice *d, int reg)
{
uint8_t type;
@@ -159,11 +158,8 @@ void pci_device_deassert_intx(PCIDevice *dev)
void pci_device_reset(PCIDevice *dev)
{
int r;
- /* TODO: call the below unconditionally once all pci devices
- * are qdevified */
- if (dev->qdev.info) {
- qdev_reset_all(&dev->qdev);
- }
+
+ qdev_reset_all(&dev->qdev);
dev->irq_state = 0;
pci_update_irq_status(dev);
@@ -733,11 +729,11 @@ static void pci_config_free(PCIDevice *pci_dev)
/* -1 for devfn means auto assign */
static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
- const char *name, int devfn,
- const PCIDeviceInfo *info)
+ const char *name, int devfn)
{
- PCIConfigReadFunc *config_read = info->config_read;
- PCIConfigWriteFunc *config_write = info->config_write;
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
+ PCIConfigReadFunc *config_read = pc->config_read;
+ PCIConfigWriteFunc *config_write = pc->config_write;
if (devfn < 0) {
for(devfn = bus->devfn_min ; devfn < ARRAY_SIZE(bus->devices);
@@ -759,29 +755,29 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
pci_dev->irq_state = 0;
pci_config_alloc(pci_dev);
- pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
- pci_config_set_device_id(pci_dev->config, info->device_id);
- pci_config_set_revision(pci_dev->config, info->revision);
- pci_config_set_class(pci_dev->config, info->class_id);
+ pci_config_set_vendor_id(pci_dev->config, pc->vendor_id);
+ pci_config_set_device_id(pci_dev->config, pc->device_id);
+ pci_config_set_revision(pci_dev->config, pc->revision);
+ pci_config_set_class(pci_dev->config, pc->class_id);
- if (!info->is_bridge) {
- if (info->subsystem_vendor_id || info->subsystem_id) {
+ if (!pc->is_bridge) {
+ if (pc->subsystem_vendor_id || pc->subsystem_id) {
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID,
- info->subsystem_vendor_id);
+ pc->subsystem_vendor_id);
pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID,
- info->subsystem_id);
+ pc->subsystem_id);
} else {
pci_set_default_subsystem_id(pci_dev);
}
} else {
/* subsystem_vendor_id/subsystem_id are only for header type 0 */
- assert(!info->subsystem_vendor_id);
- assert(!info->subsystem_id);
+ assert(!pc->subsystem_vendor_id);
+ assert(!pc->subsystem_id);
}
pci_init_cmask(pci_dev);
pci_init_wmask(pci_dev);
pci_init_w1cmask(pci_dev);
- if (info->is_bridge) {
+ if (pc->is_bridge) {
pci_init_wmask_bridge(pci_dev);
}
if (pci_init_multifunction(bus, pci_dev)) {
@@ -808,26 +804,6 @@ static void do_pci_unregister_device(PCIDevice *pci_dev)
pci_config_free(pci_dev);
}
-/* TODO: obsolete. eliminate this once all pci devices are qdevifed. */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
- int instance_size, int devfn,
- PCIConfigReadFunc *config_read,
- PCIConfigWriteFunc *config_write)
-{
- PCIDevice *pci_dev;
- PCIDeviceInfo info = {
- .config_read = config_read,
- .config_write = config_write,
- };
-
- pci_dev = g_malloc0(instance_size);
- pci_dev = do_pci_register_device(pci_dev, bus, name, devfn, &info);
- if (pci_dev == NULL) {
- hw_error("PCI: can't register device\n");
- }
- return pci_dev;
-}
-
static void pci_unregister_io_regions(PCIDevice *pci_dev)
{
PCIIORegion *r;
@@ -843,12 +819,12 @@ static void pci_unregister_io_regions(PCIDevice *pci_dev)
static int pci_unregister_device(DeviceState *dev)
{
- PCIDevice *pci_dev = DO_UPCAST(PCIDevice, qdev, dev);
- PCIDeviceInfo *info = DO_UPCAST(PCIDeviceInfo, qdev, dev->info);
+ PCIDevice *pci_dev = PCI_DEVICE(dev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
int ret = 0;
- if (info->exit)
- ret = info->exit(pci_dev);
+ if (pc->exit)
+ ret = pc->exit(pci_dev);
if (ret)
return ret;
@@ -1477,31 +1453,32 @@ PCIDevice *pci_find_device(PCIBus *bus, int bus_num, uint8_t devfn)
return bus->devices[devfn];
}
-static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int pci_qdev_init(DeviceState *qdev)
{
PCIDevice *pci_dev = (PCIDevice *)qdev;
- PCIDeviceInfo *info = container_of(base, PCIDeviceInfo, qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(pci_dev);
PCIBus *bus;
int rc;
bool is_default_rom;
/* initialize cap_present for pci_is_express() and pci_config_size() */
- if (info->is_express) {
+ if (pc->is_express) {
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
bus = FROM_QBUS(PCIBus, qdev_get_parent_bus(qdev));
- pci_dev = do_pci_register_device(pci_dev, bus, base->name,
- pci_dev->devfn, info);
+ pci_dev = do_pci_register_device(pci_dev, bus,
+ object_get_typename(OBJECT(qdev)),
+ pci_dev->devfn);
if (pci_dev == NULL)
return -1;
- if (qdev->hotplugged && info->no_hotplug) {
- qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ if (qdev->hotplugged && pc->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(pci_dev)));
do_pci_unregister_device(pci_dev);
return -1;
}
- if (info->init) {
- rc = info->init(pci_dev);
+ if (pc->init) {
+ rc = pc->init(pci_dev);
if (rc != 0) {
do_pci_unregister_device(pci_dev);
return rc;
@@ -1510,8 +1487,8 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
/* rom loading */
is_default_rom = false;
- if (pci_dev->romfile == NULL && info->romfile != NULL) {
- pci_dev->romfile = g_strdup(info->romfile);
+ if (pci_dev->romfile == NULL && pc->romfile != NULL) {
+ pci_dev->romfile = g_strdup(pc->romfile);
is_default_rom = true;
}
pci_add_option_rom(pci_dev, is_default_rom);
@@ -1533,34 +1510,18 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int pci_unplug_device(DeviceState *qdev)
{
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
+ PCIDevice *dev = PCI_DEVICE(qdev);
+ PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
- if (info->no_hotplug) {
- qerror_report(QERR_DEVICE_NO_HOTPLUG, info->qdev.name);
+ if (pc->no_hotplug) {
+ qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
return -1;
}
+ object_unparent(OBJECT(dev));
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
PCI_HOTPLUG_DISABLED);
}
-void pci_qdev_register(PCIDeviceInfo *info)
-{
- info->qdev.init = pci_qdev_init;
- info->qdev.unplug = pci_unplug_device;
- info->qdev.exit = pci_unregister_device;
- info->qdev.bus_info = &pci_bus_info;
- qdev_register(&info->qdev);
-}
-
-void pci_qdev_register_many(PCIDeviceInfo *info)
-{
- while (info->qdev.name) {
- pci_qdev_register(info);
- info++;
- }
-}
-
PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
const char *name)
{
@@ -1569,22 +1530,7 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
dev = qdev_create(&bus->qbus, name);
qdev_prop_set_uint32(dev, "addr", devfn);
qdev_prop_set_bit(dev, "multifunction", multifunction);
- return DO_UPCAST(PCIDevice, qdev, dev);
-}
-
-PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
- bool multifunction,
- const char *name)
-{
- DeviceState *dev;
-
- dev = qdev_try_create(&bus->qbus, name);
- if (!dev) {
- return NULL;
- }
- qdev_prop_set_uint32(dev, "addr", devfn);
- qdev_prop_set_bit(dev, "multifunction", multifunction);
- return DO_UPCAST(PCIDevice, qdev, dev);
+ return PCI_DEVICE(dev);
}
PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
@@ -1606,11 +1552,6 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name)
return pci_create_simple_multifunction(bus, devfn, false, name);
}
-PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name)
-{
- return pci_try_create_multifunction(bus, devfn, false, name);
-}
-
static int pci_find_space(PCIDevice *pdev, uint8_t size)
{
int config_size = pci_config_size(pdev);
@@ -1724,6 +1665,7 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
char *path;
void *ptr;
char name[32];
+ const VMStateDescription *vmsd;
if (!pdev->romfile)
return 0;
@@ -1760,10 +1702,13 @@ static int pci_add_option_rom(PCIDevice *pdev, bool is_default_rom)
size = 1 << qemu_fls(size);
}
- if (pdev->qdev.info->vmsd)
- snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->vmsd->name);
- else
- snprintf(name, sizeof(name), "%s.rom", pdev->qdev.info->name);
+ vmsd = qdev_get_vmsd(DEVICE(pdev));
+
+ if (vmsd) {
+ snprintf(name, sizeof(name), "%s.rom", vmsd->name);
+ } else {
+ snprintf(name, sizeof(name), "%s.rom", object_get_typename(OBJECT(pdev)));
+ }
pdev->has_rom = true;
memory_region_init_ram(&pdev->rom, name, size);
vmstate_register_ram(&pdev->rom, &pdev->qdev);
@@ -2004,9 +1949,8 @@ static int pci_qdev_find_recursive(PCIBus *bus,
}
/* roughly check if given qdev is pci device */
- if (qdev->info->init == &pci_qdev_init &&
- qdev->parent_bus->info == &pci_bus_info) {
- *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
+ if (object_dynamic_cast(OBJECT(qdev), TYPE_PCI_DEVICE)) {
+ *pdev = PCI_DEVICE(qdev);
return 0;
}
return -EINVAL;
@@ -2040,3 +1984,28 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev)
{
return dev->bus->address_space_io;
}
+
+static void pci_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = pci_qdev_init;
+ k->unplug = pci_unplug_device;
+ k->exit = pci_unregister_device;
+ k->bus_info = &pci_bus_info;
+}
+
+static TypeInfo pci_device_type_info = {
+ .name = TYPE_PCI_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .abstract = true,
+ .class_size = sizeof(PCIDeviceClass),
+ .class_init = pci_device_class_init,
+};
+
+static void pci_register_devices(void)
+{
+ type_register_static(&pci_device_type_info);
+}
+
+device_init(pci_register_devices);
diff --git a/hw/pci.h b/hw/pci.h
index 0d2cff6fec..33b0b184ea 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -127,6 +127,46 @@ enum {
QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
};
+#define TYPE_PCI_DEVICE "pci-device"
+#define PCI_DEVICE(obj) \
+ OBJECT_CHECK(PCIDevice, (obj), TYPE_PCI_DEVICE)
+#define PCI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(PCIDeviceClass, (klass), TYPE_PCI_DEVICE)
+#define PCI_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(PCIDeviceClass, (obj), TYPE_PCI_DEVICE)
+
+typedef struct PCIDeviceClass {
+ DeviceClass parent_class;
+
+ int (*init)(PCIDevice *dev);
+ PCIUnregisterFunc *exit;
+ PCIConfigReadFunc *config_read;
+ PCIConfigWriteFunc *config_write;
+
+ uint16_t vendor_id;
+ uint16_t device_id;
+ uint8_t revision;
+ uint16_t class_id;
+ uint16_t subsystem_vendor_id; /* only for header type = 0 */
+ uint16_t subsystem_id; /* only for header type = 0 */
+
+ /*
+ * pci-to-pci bridge or normal device.
+ * This doesn't mean pci host switch.
+ * When card bus bridge is supported, this would be enhanced.
+ */
+ int is_bridge;
+
+ /* pcie stuff */
+ int is_express; /* is this device pci express? */
+
+ /* device isn't hot-pluggable */
+ int no_hotplug;
+
+ /* rom bar */
+ const char *romfile;
+} PCIDeviceClass;
+
struct PCIDevice {
DeviceState qdev;
/* PCI config space */
@@ -196,11 +236,6 @@ struct PCIDevice {
uint32_t rom_bar;
};
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
- int instance_size, int devfn,
- PCIConfigReadFunc *config_read,
- PCIConfigWriteFunc *config_write);
-
void pci_register_bar(PCIDevice *pci_dev, int region_num,
uint8_t attr, MemoryRegion *memory);
pcibus_t pci_get_bar_addr(PCIDevice *pci_dev, int region_num);
@@ -429,52 +464,13 @@ pci_quad_test_and_set_mask(uint8_t *config, uint64_t mask)
return val & mask;
}
-typedef int (*pci_qdev_initfn)(PCIDevice *dev);
-typedef struct {
- DeviceInfo qdev;
- pci_qdev_initfn init;
- PCIUnregisterFunc *exit;
- PCIConfigReadFunc *config_read;
- PCIConfigWriteFunc *config_write;
-
- uint16_t vendor_id;
- uint16_t device_id;
- uint8_t revision;
- uint16_t class_id;
- uint16_t subsystem_vendor_id; /* only for header type = 0 */
- uint16_t subsystem_id; /* only for header type = 0 */
-
- /*
- * pci-to-pci bridge or normal device.
- * This doesn't mean pci host switch.
- * When card bus bridge is supported, this would be enhanced.
- */
- int is_bridge;
-
- /* pcie stuff */
- int is_express; /* is this device pci express? */
-
- /* device isn't hot-pluggable */
- int no_hotplug;
-
- /* rom bar */
- const char *romfile;
-} PCIDeviceInfo;
-
-void pci_qdev_register(PCIDeviceInfo *info);
-void pci_qdev_register_many(PCIDeviceInfo *info);
-
PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction,
const char *name);
PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn,
bool multifunction,
const char *name);
-PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn,
- bool multifunction,
- const char *name);
PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name);
PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name);
-PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name);
static inline int pci_is_express(const PCIDevice *d)
{
diff --git a/hw/pci_bridge.c b/hw/pci_bridge.c
index 650d1650c5..1ed43394de 100644
--- a/hw/pci_bridge.c
+++ b/hw/pci_bridge.c
@@ -294,7 +294,7 @@ void pci_bridge_reset_reg(PCIDevice *dev)
/* default reset function for PCI-to-PCI bridge */
void pci_bridge_reset(DeviceState *qdev)
{
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *dev = PCI_DEVICE(qdev);
pci_bridge_reset_reg(dev);
}
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index 83f38934ec..e8235a7d05 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -98,6 +98,7 @@
#define PCI_DEVICE_ID_MPC8533E 0x0030
#define PCI_VENDOR_ID_INTEL 0x8086
+#define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_INTEL_82441 0x1237
#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415
#define PCI_DEVICE_ID_INTEL_82801D 0x24CD
@@ -120,3 +121,6 @@
#define PCI_VENDOR_ID_XEN 0x5853
#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001
+
+#define PCI_VENDOR_ID_NEC 0x1033
+#define PCI_DEVICE_ID_NEC_UPD720200 0x0194
diff --git a/hw/pcie.c b/hw/pcie.c
index 5c9eb2f0ac..7c92f193e7 100644
--- a/hw/pcie.c
+++ b/hw/pcie.c
@@ -203,7 +203,7 @@ static void pcie_cap_slot_event(PCIDevice *dev, PCIExpressHotPlugEvent event)
static int pcie_cap_slot_hotplug(DeviceState *qdev,
PCIDevice *pci_dev, PCIHotplugState state)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
uint8_t *exp_cap = d->config + d->exp.exp_cap;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 06b40c540c..b4c53bed6c 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -497,16 +497,24 @@ static int i8042_initfn(ISADevice *dev)
return 0;
}
-static ISADeviceInfo i8042_info = {
- .qdev.name = "i8042",
- .qdev.size = sizeof(ISAKBDState),
- .qdev.vmsd = &vmstate_kbd_isa,
- .qdev.no_user = 1,
- .init = i8042_initfn,
+static void i8042_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = i8042_initfn;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_kbd_isa;
+}
+
+static TypeInfo i8042_info = {
+ .name = "i8042",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAKBDState),
+ .class_init = i8042_class_initfn,
};
static void i8042_register(void)
{
- isa_qdev_register(&i8042_info);
+ type_register_static(&i8042_info);
}
device_init(i8042_register)
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 4e164da3ac..439f32caae 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -348,26 +348,37 @@ static void pci_reset(DeviceState *dev)
pcnet_h_reset(&d->state);
}
-static PCIDeviceInfo pcnet_info = {
- .qdev.name = "pcnet",
- .qdev.size = sizeof(PCIPCNetState),
- .qdev.reset = pci_reset,
- .qdev.vmsd = &vmstate_pci_pcnet,
- .init = pci_pcnet_init,
- .exit = pci_pcnet_uninit,
- .vendor_id = PCI_VENDOR_ID_AMD,
- .device_id = PCI_DEVICE_ID_AMD_LANCE,
- .revision = 0x10,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property pcnet_properties[] = {
+ DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pcnet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_pcnet_init;
+ k->exit = pci_pcnet_uninit;
+ k->vendor_id = PCI_VENDOR_ID_AMD;
+ k->device_id = PCI_DEVICE_ID_AMD_LANCE;
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = pci_reset;
+ dc->vmsd = &vmstate_pci_pcnet;
+ dc->props = pcnet_properties;
+}
+
+static TypeInfo pcnet_info = {
+ .name = "pcnet",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIPCNetState),
+ .class_init = pcnet_class_init,
};
static void pci_pcnet_register_devices(void)
{
- pci_qdev_register(&pcnet_info);
+ type_register_static(&pcnet_info);
}
device_init(pci_pcnet_register_devices)
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 306dc6ed7e..c53f06ef3b 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -688,7 +688,6 @@ static void pcnet_s_reset(PCNetState *s)
printf("pcnet_s_reset\n");
#endif
- s->lnkst = 0x40;
s->rdra = 0;
s->tdra = 0;
s->rap = 0;
@@ -1719,7 +1718,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
- s->nic = qemu_new_nic(info, &s->conf, dev->info->name, dev->id, s);
+ s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0");
@@ -1751,5 +1750,7 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
}
*(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
+ s->lnkst = 0x40; /* initial link state: up */
+
return 0;
}
diff --git a/hw/piix4.c b/hw/piix4.c
index 51af459073..4e7a2370cd 100644
--- a/hw/piix4.c
+++ b/hw/piix4.c
@@ -102,25 +102,30 @@ int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
return d->devfn;
}
-static PCIDeviceInfo piix4_info[] = {
- {
- .qdev.name = "PIIX4",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(PIIX4State),
- .qdev.vmsd = &vmstate_piix4,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix4_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_0, // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
- .class_id = PCI_CLASS_BRIDGE_ISA,
- },{
- /* end of list */
- }
+static void piix4_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = piix4_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB_0;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+ dc->desc = "ISA bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_piix4;
+}
+
+static TypeInfo piix4_info = {
+ .name = "PIIX4",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX4State),
+ .class_init = piix4_class_init,
};
static void piix4_register(void)
{
- pci_qdev_register_many(piix4_info);
+ type_register_static(&piix4_info);
}
device_init(piix4_register);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 3652522e58..190642733f 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -277,7 +277,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
address_space_io, 0);
s->bus = b;
qdev_init_nofail(dev);
- qdev_property_add_child(qdev_get_root(), "i440fx", dev, NULL);
+ object_property_add_child(object_get_root(), "i440fx", OBJECT(dev), NULL);
d = pci_create_simple(b, 0, device_name);
*pi440fx_state = DO_UPCAST(PCII440FXState, dev, d);
@@ -316,7 +316,7 @@ static PCIBus *i440fx_common_init(const char *device_name,
pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
PIIX_NUM_PIRQS);
}
- qdev_property_add_child(dev, "piix3", &piix3->dev.qdev, NULL);
+ object_property_add_child(OBJECT(dev), "piix3", OBJECT(piix3), NULL);
piix3->pic = pic;
*isa_bus = DO_UPCAST(ISABus, qbus,
qdev_get_child_bus(&piix3->dev.qdev, "isa.0"));
@@ -502,60 +502,98 @@ static int piix3_initfn(PCIDevice *dev)
return 0;
}
-static PCIDeviceInfo i440fx_info[] = {
- {
- .qdev.name = "i440FX",
- .qdev.desc = "Host bridge",
- .qdev.size = sizeof(PCII440FXState),
- .qdev.vmsd = &vmstate_i440fx,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = i440fx_initfn,
- .config_write = i440fx_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82441,
- .revision = 0x02,
- .class_id = PCI_CLASS_BRIDGE_HOST,
- },{
- .qdev.name = "PIIX3",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(PIIX3State),
- .qdev.vmsd = &vmstate_piix3,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix3_initfn,
- .config_write = piix3_write_config,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- .class_id = PCI_CLASS_BRIDGE_ISA,
- },{
- .qdev.name = "PIIX3-xen",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(PIIX3State),
- .qdev.vmsd = &vmstate_piix3,
- .qdev.no_user = 1,
- .no_hotplug = 1,
- .init = piix3_initfn,
- .config_write = piix3_write_config_xen,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_0, // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- .class_id = PCI_CLASS_BRIDGE_ISA,
- },{
- /* end of list */
- }
+static void piix3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "ISA bridge";
+ dc->vmsd = &vmstate_piix3;
+ dc->no_user = 1,
+ k->no_hotplug = 1;
+ k->init = piix3_initfn;
+ k->config_write = piix3_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+}
+
+static TypeInfo piix3_info = {
+ .name = "PIIX3",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX3State),
+ .class_init = piix3_class_init,
+};
+
+static void piix3_xen_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ dc->desc = "ISA bridge";
+ dc->vmsd = &vmstate_piix3;
+ dc->no_user = 1;
+ k->no_hotplug = 1;
+ k->init = piix3_initfn;
+ k->config_write = piix3_write_config_xen;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+};
+
+static TypeInfo piix3_xen_info = {
+ .name = "PIIX3-xen",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PIIX3State),
+ .class_init = piix3_xen_class_init,
};
-static SysBusDeviceInfo i440fx_pcihost_info = {
- .init = i440fx_pcihost_initfn,
- .qdev.name = "i440FX-pcihost",
- .qdev.fw_name = "pci",
- .qdev.size = sizeof(I440FXState),
- .qdev.no_user = 1,
+static void i440fx_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = i440fx_initfn;
+ k->config_write = i440fx_write_config;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82441;
+ k->revision = 0x02;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->desc = "Host bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_i440fx;
+}
+
+static TypeInfo i440fx_info = {
+ .name = "i440FX",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCII440FXState),
+ .class_init = i440fx_class_init,
+};
+
+static void i440fx_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = i440fx_pcihost_initfn;
+ dc->fw_name = "pci";
+ dc->no_user = 1;
+}
+
+static TypeInfo i440fx_pcihost_info = {
+ .name = "i440FX-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(I440FXState),
+ .class_init = i440fx_pcihost_class_init,
};
static void i440fx_register(void)
{
- sysbus_register_withprop(&i440fx_pcihost_info);
- pci_qdev_register_many(i440fx_info);
+ type_register_static(&i440fx_info);
+ type_register_static(&piix3_info);
+ type_register_static(&piix3_xen_info);
+ type_register_static(&i440fx_pcihost_info);
}
device_init(i440fx_register);
diff --git a/hw/pl011.c b/hw/pl011.c
index 1b05d76a78..752cbf9725 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -264,7 +264,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
sysbus_init_mmio(dev, &s->iomem);
sysbus_init_irq(dev, &s->irq);
s->id = id;
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
s->read_trigger = 1;
s->ifl = 0x12;
@@ -278,22 +278,48 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id)
return 0;
}
-static int pl011_init_arm(SysBusDevice *dev)
+static int pl011_arm_init(SysBusDevice *dev)
{
return pl011_init(dev, pl011_id_arm);
}
-static int pl011_init_luminary(SysBusDevice *dev)
+static int pl011_luminary_init(SysBusDevice *dev)
{
return pl011_init(dev, pl011_id_luminary);
}
+static void pl011_arm_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pl011_arm_init;
+}
+
+static TypeInfo pl011_arm_info = {
+ .name = "pl011",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl011_state),
+ .class_init = pl011_arm_class_init,
+};
+
+static void pl011_luminary_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pl011_luminary_init;
+}
+
+static TypeInfo pl011_luminary_info = {
+ .name = "pl011_luminary",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl011_state),
+ .class_init = pl011_luminary_class_init,
+};
+
static void pl011_register_devices(void)
{
- sysbus_register_dev("pl011", sizeof(pl011_state),
- pl011_init_arm);
- sysbus_register_dev("pl011_luminary", sizeof(pl011_state),
- pl011_init_luminary);
+ type_register_static(&pl011_arm_info);
+ type_register_static(&pl011_luminary_info);
}
device_init(pl011_register_devices)
diff --git a/hw/pl022.c b/hw/pl022.c
index d43e4a29da..30bd3442bb 100644
--- a/hw/pl022.c
+++ b/hw/pl022.c
@@ -285,9 +285,23 @@ static int pl022_init(SysBusDevice *dev)
return 0;
}
+static void pl022_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pl022_init;
+}
+
+static TypeInfo pl022_info = {
+ .name = "pl022",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl022_state),
+ .class_init = pl022_class_init,
+};
+
static void pl022_register_devices(void)
{
- sysbus_register_dev("pl022", sizeof(pl022_state), pl022_init);
+ type_register_static(&pl022_info);
}
device_init(pl022_register_devices)
diff --git a/hw/pl031.c b/hw/pl031.c
index 2fb0c8ef24..8416a609ef 100644
--- a/hw/pl031.c
+++ b/hw/pl031.c
@@ -213,17 +213,26 @@ static int pl031_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo pl031_info = {
- .init = pl031_init,
- .qdev.name = "pl031",
- .qdev.size = sizeof(pl031_state),
- .qdev.vmsd = &vmstate_pl031,
- .qdev.no_user = 1,
+static void pl031_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl031_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl031;
+}
+
+static TypeInfo pl031_info = {
+ .name = "pl031",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl031_state),
+ .class_init = pl031_class_init,
};
static void pl031_register_devices(void)
{
- sysbus_register_withprop(&pl031_info);
+ type_register_static(&pl031_info);
}
device_init(pl031_register_devices)
diff --git a/hw/pl041.c b/hw/pl041.c
index 4585ccf9c0..6d99c9cbbc 100644
--- a/hw/pl041.c
+++ b/hw/pl041.c
@@ -613,24 +613,34 @@ static const VMStateDescription vmstate_pl041 = {
}
};
-static SysBusDeviceInfo pl041_device_info = {
- .init = pl041_init,
- .qdev.name = "pl041",
- .qdev.size = sizeof(pl041_state),
- .qdev.vmsd = &vmstate_pl041,
- .qdev.reset = pl041_device_reset,
- .qdev.no_user = 1,
- .qdev.props = (Property[]) {
- /* Non-compact FIFO depth property */
- DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state,
- fifo_depth, DEFAULT_FIFO_DEPTH),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pl041_device_properties[] = {
+ /* Non-compact FIFO depth property */
+ DEFINE_PROP_UINT32("nc_fifo_depth", pl041_state, fifo_depth, DEFAULT_FIFO_DEPTH),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pl041_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl041_init;
+ dc->no_user = 1;
+ dc->reset = pl041_device_reset;
+ dc->vmsd = &vmstate_pl041;
+ dc->props = pl041_device_properties;
+}
+
+static TypeInfo pl041_device_info = {
+ .name = "pl041",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl041_state),
+ .class_init = pl041_device_class_init,
};
static void pl041_register_device(void)
{
- sysbus_register_withprop(&pl041_device_info);
+ type_register_static(&pl041_device_info);
}
device_init(pl041_register_device)
diff --git a/hw/pl050.c b/hw/pl050.c
index 8182a1c82d..b0094ac9b3 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -157,24 +157,42 @@ static int pl050_init_mouse(SysBusDevice *dev)
return pl050_init(dev, 1);
}
-static SysBusDeviceInfo pl050_kbd_info = {
- .init = pl050_init_keyboard,
- .qdev.name = "pl050_keyboard",
- .qdev.size = sizeof(pl050_state),
- .qdev.vmsd = &vmstate_pl050,
+static void pl050_kbd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl050_init_keyboard;
+ dc->vmsd = &vmstate_pl050;
+}
+
+static TypeInfo pl050_kbd_info = {
+ .name = "pl050_keyboard",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl050_state),
+ .class_init = pl050_kbd_class_init,
};
-static SysBusDeviceInfo pl050_mouse_info = {
- .init = pl050_init_mouse,
- .qdev.name = "pl050_mouse",
- .qdev.size = sizeof(pl050_state),
- .qdev.vmsd = &vmstate_pl050,
+static void pl050_mouse_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl050_init_mouse;
+ dc->vmsd = &vmstate_pl050;
+}
+
+static TypeInfo pl050_mouse_info = {
+ .name = "pl050_mouse",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl050_state),
+ .class_init = pl050_mouse_class_init,
};
static void pl050_register_devices(void)
{
- sysbus_register_withprop(&pl050_kbd_info);
- sysbus_register_withprop(&pl050_mouse_info);
+ type_register_static(&pl050_kbd_info);
+ type_register_static(&pl050_mouse_info);
}
device_init(pl050_register_devices)
diff --git a/hw/pl061.c b/hw/pl061.c
index f33ae84408..3136c99423 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -293,24 +293,42 @@ static int pl061_init_arm(SysBusDevice *dev)
return pl061_init(dev, pl061_id);
}
-static SysBusDeviceInfo pl061_info = {
- .init = pl061_init_arm,
- .qdev.name = "pl061",
- .qdev.size = sizeof(pl061_state),
- .qdev.vmsd = &vmstate_pl061,
+static void pl061_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl061_init_arm;
+ dc->vmsd = &vmstate_pl061;
+}
+
+static TypeInfo pl061_info = {
+ .name = "pl061",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl061_state),
+ .class_init = pl061_class_init,
};
-static SysBusDeviceInfo pl061_luminary_info = {
- .init = pl061_init_luminary,
- .qdev.name = "pl061_luminary",
- .qdev.size = sizeof(pl061_state),
- .qdev.vmsd = &vmstate_pl061,
+static void pl061_luminary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl061_init_luminary;
+ dc->vmsd = &vmstate_pl061;
+}
+
+static TypeInfo pl061_luminary_info = {
+ .name = "pl061_luminary",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl061_state),
+ .class_init = pl061_luminary_class_init,
};
static void pl061_register_devices(void)
{
- sysbus_register_withprop(&pl061_info);
- sysbus_register_withprop(&pl061_luminary_info);
+ type_register_static(&pl061_info);
+ type_register_static(&pl061_luminary_info);
}
device_init(pl061_register_devices)
diff --git a/hw/pl080.c b/hw/pl080.c
index e001df92e0..4405d1823b 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -373,28 +373,46 @@ static int pl081_init(SysBusDevice *dev)
return pl08x_init(dev, 2);
}
-static SysBusDeviceInfo pl080_info = {
- .init = pl080_init,
- .qdev.name = "pl080",
- .qdev.size = sizeof(pl080_state),
- .qdev.vmsd = &vmstate_pl080,
- .qdev.no_user = 1,
+static void pl080_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl080_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl080;
+}
+
+static TypeInfo pl080_info = {
+ .name = "pl080",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl080_state),
+ .class_init = pl080_class_init,
};
-static SysBusDeviceInfo pl081_info = {
- .init = pl081_init,
- .qdev.name = "pl081",
- .qdev.size = sizeof(pl080_state),
- .qdev.vmsd = &vmstate_pl080,
- .qdev.no_user = 1,
+static void pl081_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl081_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl080;
+}
+
+static TypeInfo pl081_info = {
+ .name = "pl081",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl080_state),
+ .class_init = pl081_class_init,
};
/* The PL080 and PL081 are the same except for the number of channels
they implement (8 and 2 respectively). */
static void pl080_register_devices(void)
{
- sysbus_register_withprop(&pl080_info);
- sysbus_register_withprop(&pl081_info);
+ type_register_static(&pl080_info);
+ type_register_static(&pl081_info);
}
device_init(pl080_register_devices)
diff --git a/hw/pl110.c b/hw/pl110.c
index 0e1f415aeb..86e95a3ffd 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -469,35 +469,62 @@ static int pl111_init(SysBusDevice *dev)
return pl110_init(dev);
}
-static SysBusDeviceInfo pl110_info = {
- .init = pl110_init,
- .qdev.name = "pl110",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl110_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl110_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_info = {
+ .name = "pl110",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl110_class_init,
};
-static SysBusDeviceInfo pl110_versatile_info = {
- .init = pl110_versatile_init,
- .qdev.name = "pl110_versatile",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl110_versatile_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl110_versatile_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl110_versatile_info = {
+ .name = "pl110_versatile",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl110_versatile_class_init,
};
-static SysBusDeviceInfo pl111_info = {
- .init = pl111_init,
- .qdev.name = "pl111",
- .qdev.size = sizeof(pl110_state),
- .qdev.vmsd = &vmstate_pl110,
- .qdev.no_user = 1,
+static void pl111_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl111_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_pl110;
+}
+
+static TypeInfo pl111_info = {
+ .name = "pl111",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl110_state),
+ .class_init = pl111_class_init,
};
static void pl110_register_devices(void)
{
- sysbus_register_withprop(&pl110_info);
- sysbus_register_withprop(&pl110_versatile_info);
- sysbus_register_withprop(&pl111_info);
+ type_register_static(&pl110_info);
+ type_register_static(&pl110_versatile_info);
+ type_register_static(&pl111_info);
}
device_init(pl110_register_devices)
diff --git a/hw/pl181.c b/hw/pl181.c
index b79aa418fa..ae636e220e 100644
--- a/hw/pl181.c
+++ b/hw/pl181.c
@@ -487,18 +487,27 @@ static int pl181_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo pl181_info = {
- .init = pl181_init,
- .qdev.name = "pl181",
- .qdev.size = sizeof(pl181_state),
- .qdev.vmsd = &vmstate_pl181,
- .qdev.reset = pl181_reset,
- .qdev.no_user = 1,
+static void pl181_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *k = DEVICE_CLASS(klass);
+
+ sdc->init = pl181_init;
+ k->vmsd = &vmstate_pl181;
+ k->reset = pl181_reset;
+ k->no_user = 1;
+}
+
+static TypeInfo pl181_info = {
+ .name = "pl181",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl181_state),
+ .class_init = pl181_class_init,
};
static void pl181_register_devices(void)
{
- sysbus_register_withprop(&pl181_info);
+ type_register_static(&pl181_info);
}
device_init(pl181_register_devices)
diff --git a/hw/pl190.c b/hw/pl190.c
index 6fc2656f69..956ab21c6a 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -255,18 +255,27 @@ static const VMStateDescription vmstate_pl190 = {
}
};
-static SysBusDeviceInfo pl190_info = {
- .init = pl190_init,
- .qdev.name = "pl190",
- .qdev.size = sizeof(pl190_state),
- .qdev.vmsd = &vmstate_pl190,
- .qdev.reset = pl190_reset,
- .qdev.no_user = 1,
+static void pl190_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pl190_init;
+ dc->no_user = 1;
+ dc->reset = pl190_reset;
+ dc->vmsd = &vmstate_pl190;
+}
+
+static TypeInfo pl190_info = {
+ .name = "pl190",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(pl190_state),
+ .class_init = pl190_class_init,
};
static void pl190_register_devices(void)
{
- sysbus_register_withprop(&pl190_info);
+ type_register_static(&pl190_info);
}
device_init(pl190_register_devices)
diff --git a/hw/ppc440.c b/hw/ppc440.c
deleted file mode 100644
index cd8a95d52b..0000000000
--- a/hw/ppc440.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Qemu PowerPC 440 chip emulation
- *
- * Copyright 2007 IBM Corporation.
- * Authors:
- * Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * Hollis Blanchard <hollisb@us.ibm.com>
- *
- * This work is licensed under the GNU GPL license version 2 or later.
- *
- */
-
-#include "hw.h"
-#include "pc.h"
-#include "isa.h"
-#include "ppc.h"
-#include "ppc4xx.h"
-#include "ppc440.h"
-#include "ppc405.h"
-#include "sysemu.h"
-#include "kvm.h"
-
-#define PPC440EP_PCI_CONFIG 0xeec00000
-#define PPC440EP_PCI_INTACK 0xeed00000
-#define PPC440EP_PCI_SPECIAL 0xeed00000
-#define PPC440EP_PCI_REGS 0xef400000
-#define PPC440EP_PCI_IO 0xe8000000
-#define PPC440EP_PCI_IOLEN 0x00010000
-
-#define PPC440EP_SDRAM_NR_BANKS 4
-
-static const unsigned int ppc440ep_sdram_bank_sizes[] = {
- 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
-};
-
-CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size,
- PCIBus **pcip, const unsigned int pci_irq_nrs[4],
- int do_init, const char *cpu_model)
-{
- MemoryRegion *ram_memories
- = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
- target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
- target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
- CPUState *env;
- qemu_irq *pic;
- qemu_irq *irqs;
- qemu_irq *pci_irqs;
-
- if (cpu_model == NULL) {
- cpu_model = "440-Xilinx"; // XXX: should be 440EP
- }
- env = cpu_init(cpu_model);
- if (!env) {
- fprintf(stderr, "Unable to initialize CPU!\n");
- exit(1);
- }
-
- ppc_dcr_init(env, NULL, NULL);
-
- /* interrupt controller */
- irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
- irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
- irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
- pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
-
- /* SDRAM controller */
- memset(ram_bases, 0, sizeof(ram_bases));
- memset(ram_sizes, 0, sizeof(ram_sizes));
- *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS,
- ram_memories,
- ram_bases, ram_sizes,
- ppc440ep_sdram_bank_sizes);
- /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
- ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
- ram_bases, ram_sizes, do_init);
-
- /* PCI */
- pci_irqs = g_malloc(sizeof(qemu_irq) * 4);
- pci_irqs[0] = pic[pci_irq_nrs[0]];
- pci_irqs[1] = pic[pci_irq_nrs[1]];
- pci_irqs[2] = pic[pci_irq_nrs[2]];
- pci_irqs[3] = pic[pci_irq_nrs[3]];
- *pcip = ppc4xx_pci_init(env, pci_irqs,
- PPC440EP_PCI_CONFIG,
- PPC440EP_PCI_INTACK,
- PPC440EP_PCI_SPECIAL,
- PPC440EP_PCI_REGS);
- if (!*pcip)
- printf("couldn't create PCI controller!\n");
-
- isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
-
- if (serial_hds[0] != NULL) {
- serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
- DEVICE_BIG_ENDIAN);
- }
- if (serial_hds[1] != NULL) {
- serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
- PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
- DEVICE_BIG_ENDIAN);
- }
-
- return env;
-}
diff --git a/hw/ppc440.h b/hw/ppc440.h
deleted file mode 100644
index 9c27c36fd0..0000000000
--- a/hw/ppc440.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Qemu PowerPC 440 board emualtion
- *
- * Copyright 2007 IBM Corporation.
- * Authors: Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- *
- * This work is licensed under the GNU GPL licence version 2 or later
- *
- */
-
-#ifndef QEMU_PPC440_H
-#define QEMU_PPC440_H
-
-#include "hw.h"
-
-CPUState *ppc440ep_init(MemoryRegion *address_space, ram_addr_t *ram_size,
- PCIBus **pcip, const unsigned int pci_irq_nrs[4],
- int do_init, const char *cpu_model);
-
-#endif
diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c
index b734e3a56c..f86b16838a 100644
--- a/hw/ppc440_bamboo.c
+++ b/hw/ppc440_bamboo.c
@@ -3,9 +3,9 @@
*
* Copyright 2007 IBM Corporation.
* Authors:
- * Jerone Young <jyoung5@us.ibm.com>
- * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
- * Hollis Blanchard <hollisb@us.ibm.com>
+ * Jerone Young <jyoung5@us.ibm.com>
+ * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
*
* This work is licensed under the GNU GPL license version 2 or later.
*
@@ -17,13 +17,17 @@
#include "hw.h"
#include "pci.h"
#include "boards.h"
-#include "ppc440.h"
#include "kvm.h"
#include "kvm_ppc.h"
#include "device_tree.h"
#include "loader.h"
#include "elf.h"
#include "exec-memory.h"
+#include "pc.h"
+#include "ppc.h"
+#include "ppc405.h"
+#include "sysemu.h"
+#include "sysbus.h"
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
@@ -32,6 +36,21 @@
#define FDT_ADDR 0x1800000
#define RAMDISK_ADDR 0x1900000
+#define PPC440EP_PCI_CONFIG 0xeec00000
+#define PPC440EP_PCI_INTACK 0xeed00000
+#define PPC440EP_PCI_SPECIAL 0xeed00000
+#define PPC440EP_PCI_REGS 0xef400000
+#define PPC440EP_PCI_IO 0xe8000000
+#define PPC440EP_PCI_IOLEN 0x00010000
+
+#define PPC440EP_SDRAM_NR_BANKS 4
+
+static const unsigned int ppc440ep_sdram_bank_sizes[] = {
+ 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0
+};
+
+static target_phys_addr_t entry;
+
static int bamboo_load_device_tree(target_phys_addr_t addr,
uint32_t ramsize,
target_phys_addr_t initrd_base,
@@ -101,6 +120,42 @@ out:
return ret;
}
+/* Create reset TLB entries for BookE, spanning the 32bit addr space. */
+static void mmubooke_create_initial_mapping(CPUState *env,
+ target_ulong va,
+ target_phys_addr_t pa)
+{
+ ppcemb_tlb_t *tlb = &env->tlb.tlbe[0];
+
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0x80000000 */
+ tlb->EPN = va & TARGET_PAGE_MASK;
+ tlb->RPN = pa & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+
+ tlb = &env->tlb.tlbe[1];
+ tlb->attr = 0;
+ tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
+ tlb->size = 1 << 31; /* up to 0xffffffff */
+ tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
+ tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
+ tlb->PID = 0;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+
+ cpu_reset(env);
+ env->gpr[1] = (16<<20) - 8;
+ env->gpr[3] = FDT_ADDR;
+ env->nip = entry;
+
+ /* Create a mapping for the kernel. */
+ mmubooke_create_initial_mapping(env, 0, 0);
+}
+
static void bamboo_init(ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename,
@@ -110,19 +165,76 @@ static void bamboo_init(ram_addr_t ram_size,
{
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *ram_memories
+ = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories));
+ target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS];
+ target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS];
+ qemu_irq *pic;
+ qemu_irq *irqs;
PCIBus *pcibus;
CPUState *env;
uint64_t elf_entry;
uint64_t elf_lowaddr;
- target_phys_addr_t entry = 0;
target_phys_addr_t loadaddr = 0;
target_long initrd_size = 0;
+ DeviceState *dev;
int success;
int i;
/* Setup CPU. */
- env = ppc440ep_init(address_space_mem, &ram_size, &pcibus,
- pci_irq_nrs, 1, cpu_model);
+ if (cpu_model == NULL) {
+ cpu_model = "440EP";
+ }
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to initialize CPU!\n");
+ exit(1);
+ }
+
+ qemu_register_reset(main_cpu_reset, env);
+ ppc_booke_timers_init(env, 400000000, 0);
+ ppc_dcr_init(env, NULL, NULL);
+
+ /* interrupt controller */
+ irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+ irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+ pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+
+ /* SDRAM controller */
+ memset(ram_bases, 0, sizeof(ram_bases));
+ memset(ram_sizes, 0, sizeof(ram_sizes));
+ ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS,
+ ram_memories,
+ ram_bases, ram_sizes,
+ ppc440ep_sdram_bank_sizes);
+ /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
+ ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories,
+ ram_bases, ram_sizes, 1);
+
+ /* PCI */
+ dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG,
+ pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]],
+ pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]],
+ NULL);
+ pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+ if (!pcibus) {
+ fprintf(stderr, "couldn't create PCI controller!\n");
+ exit(1);
+ }
+
+ isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN);
+
+ if (serial_hds[0] != NULL) {
+ serial_mm_init(address_space_mem, 0xef600300, 0, pic[0],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[0],
+ DEVICE_BIG_ENDIAN);
+ }
+ if (serial_hds[1] != NULL) {
+ serial_mm_init(address_space_mem, 0xef600400, 0, pic[1],
+ PPC_SERIAL_MM_BAUDBASE, serial_hds[1],
+ DEVICE_BIG_ENDIAN);
+ }
if (pcibus) {
/* Register network interfaces. */
@@ -169,12 +281,6 @@ static void bamboo_init(ram_addr_t ram_size,
fprintf(stderr, "couldn't load device tree\n");
exit(1);
}
-
- /* Set initial guest state. */
- env->gpr[1] = (16<<20) - 8;
- env->gpr[3] = FDT_ADDR;
- env->nip = entry;
- /* XXX we currently depend on KVM to create some initial TLB entries. */
}
if (kvm_enabled())
@@ -182,34 +288,14 @@ static void bamboo_init(ram_addr_t ram_size,
}
static QEMUMachine bamboo_machine = {
- .name = "bamboo-0.13",
- .alias = "bamboo",
- .desc = "bamboo",
- .init = bamboo_init,
-};
-
-static QEMUMachine bamboo_machine_v0_12 = {
- .name = "bamboo-0.12",
+ .name = "bamboo",
.desc = "bamboo",
.init = bamboo_init,
- .compat_props = (GlobalProperty[]) {
- {
- .driver = "virtio-serial-pci",
- .property = "max_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },
- { /* end of list */ }
- },
};
static void bamboo_machine_init(void)
{
qemu_register_machine(&bamboo_machine);
- qemu_register_machine(&bamboo_machine_v0_12);
}
machine_init(bamboo_machine_init);
diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c
index 2c69210225..d11f120d32 100644
--- a/hw/ppc4xx_pci.c
+++ b/hw/ppc4xx_pci.c
@@ -49,13 +49,14 @@ struct PCITargetMap {
#define PPC4xx_PCI_NR_PTMS 2
struct PPC4xxPCIState {
+ PCIHostState pci_state;
+
struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
+ qemu_irq irq[4];
- PCIHostState pci_state;
- PCIDevice *pci_dev;
- MemoryRegion iomem_addr;
- MemoryRegion iomem_regs;
+ MemoryRegion container;
+ MemoryRegion iomem;
};
typedef struct PPC4xxPCIState PPC4xxPCIState;
@@ -83,8 +84,10 @@ typedef struct PPC4xxPCIState PPC4xxPCIState;
#define PCIL0_PTM1LA 0x34
#define PCIL0_PTM2MS 0x38
#define PCIL0_PTM2LA 0x3c
+#define PCI_REG_BASE 0x800000
#define PCI_REG_SIZE 0x40
+#define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE)
static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr,
unsigned size)
@@ -275,6 +278,10 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
qemu_irq *pci_irqs = opaque;
DPRINTF("%s: PCI irq %d\n", __func__, irq_num);
+ if (irq_num < 0) {
+ fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num);
+ return;
+ }
qemu_set_irq(pci_irqs[irq_num], level);
}
@@ -310,7 +317,6 @@ static const VMStateDescription vmstate_ppc4xx_pci = {
.minimum_version_id = 1,
.minimum_version_id_old = 1,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState),
VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1,
vmstate_pci_master_map,
struct PCIMasterMap),
@@ -322,60 +328,81 @@ static const VMStateDescription vmstate_ppc4xx_pci = {
};
/* XXX Interrupt acknowledge cycles not supported. */
-PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4],
- target_phys_addr_t config_space,
- target_phys_addr_t int_ack,
- target_phys_addr_t special_cycle,
- target_phys_addr_t registers)
+static int ppc4xx_pcihost_initfn(SysBusDevice *dev)
+{
+ PPC4xxPCIState *s;
+ PCIHostState *h;
+ PCIBus *b;
+ int i;
+
+ h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev));
+ s = DO_UPCAST(PPC4xxPCIState, pci_state, h);
+
+ for (i = 0; i < ARRAY_SIZE(s->irq); i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
+
+ b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, ppc4xx_pci_set_irq,
+ ppc4xx_pci_map_irq, s->irq, get_system_memory(),
+ get_system_io(), 0, 4);
+ s->pci_state.bus = b;
+
+ pci_create_simple(b, 0, "ppc4xx-host-bridge");
+
+ /* XXX split into 2 memory regions, one for config space, one for regs */
+ memory_region_init(&s->container, "pci-container", PCI_ALL_SIZE);
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, h,
+ "pci-conf-idx", 4);
+ memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h,
+ "pci-conf-data", 4);
+ memory_region_init_io(&s->iomem, &pci_reg_ops, s,
+ "pci.reg", PCI_REG_SIZE);
+ memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem);
+ memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem);
+ memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem);
+ sysbus_init_mmio(dev, &s->container);
+ qemu_register_reset(ppc4xx_pci_reset, s);
+
+ return 0;
+}
+
+static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->desc = "Host bridge";
+ k->vendor_id = PCI_VENDOR_ID_IBM;
+ k->device_id = PCI_DEVICE_ID_IBM_440GX;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static TypeInfo ppc4xx_host_bridge_info = {
+ .name = "ppc4xx-host-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = ppc4xx_host_bridge_class_init,
+};
+
+static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = ppc4xx_pcihost_initfn;
+ dc->vmsd = &vmstate_ppc4xx_pci;
+}
+
+static TypeInfo ppc4xx_pcihost_info = {
+ .name = "ppc4xx-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PPC4xxPCIState),
+ .class_init = ppc4xx_pcihost_class_init,
+};
+
+static void ppc4xx_pci_register(void)
{
- PPC4xxPCIState *controller;
- static int ppc4xx_pci_id;
- uint8_t *pci_conf;
-
- controller = g_malloc0(sizeof(PPC4xxPCIState));
-
- controller->pci_state.bus = pci_register_bus(NULL, "pci",
- ppc4xx_pci_set_irq,
- ppc4xx_pci_map_irq,
- pci_irqs,
- get_system_memory(),
- get_system_io(),
- 0, 4);
-
- controller->pci_dev = pci_register_device(controller->pci_state.bus,
- "host bridge", sizeof(PCIDevice),
- 0, NULL, NULL);
- pci_conf = controller->pci_dev->config;
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX);
- pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
-
- /* CFGADDR */
- memory_region_init_io(&controller->iomem_addr, &pci4xx_cfgaddr_ops,
- controller, "pci.cfgaddr", 4);
- memory_region_add_subregion(get_system_memory(),
- config_space + PCIC0_CFGADDR,
- &controller->iomem_addr);
-
- /* CFGDATA */
- memory_region_init_io(&controller->pci_state.data_mem,
- &pci_host_data_be_ops,
- &controller->pci_state, "pci-conf-data", 4);
- memory_region_add_subregion(get_system_memory(),
- config_space + PCIC0_CFGDATA,
- &controller->pci_state.data_mem);
-
- /* Internal registers */
- memory_region_init_io(&controller->iomem_regs, &pci_reg_ops, controller,
- "pci.regs", PCI_REG_SIZE);
- memory_region_add_subregion(get_system_memory(), registers,
- &controller->iomem_regs);
-
- qemu_register_reset(ppc4xx_pci_reset, controller);
-
- /* XXX load/save code not tested. */
- vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++,
- &vmstate_ppc4xx_pci, controller);
-
- return controller->pci_state.bus;
+ type_register_static(&ppc4xx_pcihost_info);
+ type_register_static(&ppc4xx_host_bridge_info);
}
+device_init(ppc4xx_pci_register);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index a746c9c3c6..506187b182 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -311,7 +311,7 @@ static void ppc_core99_init (ram_addr_t ram_size,
exit(1);
}
}
- pic = openpic_init(NULL, &pic_mem, smp_cpus, openpic_irqs, NULL);
+ pic = openpic_init(&pic_mem, smp_cpus, openpic_irqs, NULL);
if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) {
/* 970 gets a U3 bus */
pci_bus = pci_pmac_u3_init(pic, get_system_memory(), get_system_io());
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 47dab3f184..eb43fb5849 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -29,7 +29,7 @@
#include "sysemu.h"
#include "isa.h"
#include "pci.h"
-#include "prep_pci.h"
+#include "pci_host.h"
#include "usb-ohci.h"
#include "ppc.h"
#include "boards.h"
@@ -83,37 +83,9 @@ static const int ide_irq[2] = { 13, 13 };
static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-//static ISADevice *pit;
-
/* ISA IO ports bridge */
#define PPC_IO_BASE 0x80000000
-#if 0
-/* Speaker port 0x61 */
-static int speaker_data_on;
-static int dummy_refresh_clock;
-#endif
-
-static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val)
-{
-#if 0
- speaker_data_on = (val >> 1) & 1;
- pit_set_gate(pit, 2, val & 1);
-#endif
-}
-
-static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
-{
-#if 0
- int out;
- out = pit_get_out(pit, 2, qemu_get_clock_ns(vm_clock));
- dummy_refresh_clock ^= 1;
- return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
- (dummy_refresh_clock << 4);
-#endif
- return 0;
-}
-
/* PCI intack register */
/* Read-only register (?) */
static void PPC_intack_write (void *opaque, target_phys_addr_t addr,
@@ -522,9 +494,12 @@ static void ppc_prep_init (ram_addr_t ram_size,
MemoryRegion *bios = g_new(MemoryRegion, 1);
uint32_t kernel_base, initrd_base;
long kernel_size, initrd_size;
+ DeviceState *dev;
+ SysBusDevice *sys;
+ PCIHostState *pcihost;
PCIBus *pci_bus;
+ PCIDevice *pci;
ISABus *isa_bus;
- qemu_irq *i8259;
qemu_irq *cpu_exit_irq;
int ppc_boot_device;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
@@ -560,6 +535,8 @@ static void ppc_prep_init (ram_addr_t ram_size,
/* allocate and load BIOS */
memory_region_init_ram(bios, "ppc_prep.bios", BIOS_SIZE);
+ memory_region_set_readonly(bios, true);
+ memory_region_add_subregion(sysmem, (uint32_t)(-BIOS_SIZE), bios);
vmstate_register_ram_global(bios);
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
@@ -573,8 +550,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
target_phys_addr_t bios_addr;
bios_size = (bios_size + 0xfff) & ~0xfff;
bios_addr = (uint32_t)(-bios_size);
- memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, bios_addr, bios);
bios_size = load_image_targphys(filename, bios_addr, bios_size);
}
if (bios_size < 0 || bios_size > BIOS_SIZE) {
@@ -626,16 +601,34 @@ static void ppc_prep_init (ram_addr_t ram_size,
}
}
- isa_mem_base = 0xc0000000;
if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
hw_error("Only 6xx bus is supported on PREP machine\n");
}
- /* Hmm, prep has no pci-isa bridge ??? */
- isa_bus = isa_bus_new(NULL, get_system_io());
- i8259 = i8259_init(isa_bus, first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
- pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io());
- isa_bus_irqs(isa_bus, i8259);
- // pci_bus = i440fx_init();
+
+ dev = qdev_create(NULL, "raven-pcihost");
+ sys = sysbus_from_qdev(dev);
+ pcihost = DO_UPCAST(PCIHostState, busdev, sys);
+ pcihost->address_space = get_system_memory();
+ qdev_init_nofail(dev);
+ object_property_add_child(object_get_root(), "raven", OBJECT(dev), NULL);
+ pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci.0");
+ if (pci_bus == NULL) {
+ fprintf(stderr, "Couldn't create PCI host controller.\n");
+ exit(1);
+ }
+
+ /* PCI -> ISA bridge */
+ pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
+ cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
+ qdev_connect_gpio_out(&pci->qdev, 0,
+ first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+ qdev_connect_gpio_out(&pci->qdev, 1, *cpu_exit_irq);
+ sysbus_connect_irq(&pcihost->busdev, 0, qdev_get_gpio_in(&pci->qdev, 9));
+ sysbus_connect_irq(&pcihost->busdev, 1, qdev_get_gpio_in(&pci->qdev, 11));
+ sysbus_connect_irq(&pcihost->busdev, 2, qdev_get_gpio_in(&pci->qdev, 9));
+ sysbus_connect_irq(&pcihost->busdev, 3, qdev_get_gpio_in(&pci->qdev, 11));
+ isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&pci->qdev, "isa.0"));
+
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */
memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl,
"ppc-io", 0x00800000);
@@ -643,9 +636,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
/* init basic PC hardware */
pci_vga_init(pci_bus);
- // openpic = openpic_init(0x00000000, 0xF0000000, 1);
- // pit = pit_init(0x40, 0);
- rtc_init(isa_bus, 2000, NULL);
if (serial_hds[0])
serial_isa_init(isa_bus, 0, serial_hds[0]);
@@ -672,9 +662,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
}
isa_create_simple(isa_bus, "i8042");
- cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1);
- DMA_init(1, cpu_exit_irq);
-
// SB16_init();
for(i = 0; i < MAX_FD; i++) {
@@ -682,9 +669,6 @@ static void ppc_prep_init (ram_addr_t ram_size,
}
fdctrl_init_isa(isa_bus, fd);
- /* Register speaker port */
- register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
- register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
/* Register fake IO ports for PREP */
sysctrl->reset_irq = first_cpu->irq_inputs[PPC6xx_INPUT_HRESET];
register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
@@ -707,7 +691,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
usb_ohci_init_pci(pci_bus, -1);
}
- m48t59 = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
+ m48t59 = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
if (m48t59 == NULL)
return;
sysctrl->nvram = m48t59;
diff --git a/hw/ppce500_pci.c b/hw/ppce500_pci.c
index b606206e00..d5bce71429 100644
--- a/hw/ppce500_pci.c
+++ b/hw/ppce500_pci.c
@@ -339,25 +339,43 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
return 0;
}
-static PCIDeviceInfo e500_host_bridge_info = {
- .qdev.name = "e500-host-bridge",
- .qdev.desc = "Host bridge",
- .qdev.size = sizeof(PCIDevice),
- .vendor_id = PCI_VENDOR_ID_FREESCALE,
- .device_id = PCI_DEVICE_ID_MPC8533E,
- .class_id = PCI_CLASS_PROCESSOR_POWERPC,
+static void e500_host_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->vendor_id = PCI_VENDOR_ID_FREESCALE;
+ k->device_id = PCI_DEVICE_ID_MPC8533E;
+ k->class_id = PCI_CLASS_PROCESSOR_POWERPC;
+ dc->desc = "Host bridge";
+}
+
+static TypeInfo e500_host_bridge_info = {
+ .name = "e500-host-bridge",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = e500_host_bridge_class_init,
};
-static SysBusDeviceInfo e500_pcihost_info = {
- .init = e500_pcihost_initfn,
- .qdev.name = "e500-pcihost",
- .qdev.size = sizeof(PPCE500PCIState),
- .qdev.vmsd = &vmstate_ppce500_pci,
+static void e500_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = e500_pcihost_initfn;
+ dc->vmsd = &vmstate_ppce500_pci;
+}
+
+static TypeInfo e500_pcihost_info = {
+ .name = "e500-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PPCE500PCIState),
+ .class_init = e500_pcihost_class_init,
};
static void e500_pci_register(void)
{
- sysbus_register_withprop(&e500_pcihost_info);
- pci_qdev_register(&e500_host_bridge_info);
+ type_register_static(&e500_pcihost_info);
+ type_register_static(&e500_host_bridge_info);
}
device_init(e500_pci_register);
diff --git a/hw/ppce500_spin.c b/hw/ppce500_spin.c
index e7b1453855..9d648ec90a 100644
--- a/hw/ppce500_spin.c
+++ b/hw/ppce500_spin.c
@@ -203,14 +203,22 @@ static int ppce500_spin_initfn(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo ppce500_spin_info = {
- .init = ppce500_spin_initfn,
- .qdev.name = "e500-spin",
- .qdev.size = sizeof(SpinState),
+static void ppce500_spin_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ppce500_spin_initfn;
+}
+
+static TypeInfo ppce500_spin_info = {
+ .name = "e500-spin",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SpinState),
+ .class_init = ppce500_spin_class_init,
};
static void ppce500_spin_register(void)
{
- sysbus_register_withprop(&ppce500_spin_info);
+ type_register_static(&ppce500_spin_info);
}
device_init(ppce500_spin_register);
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index ea9fb6902c..40b8bb0edd 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -25,9 +25,16 @@
#include "hw.h"
#include "pci.h"
#include "pci_host.h"
-#include "prep_pci.h"
+#include "exec-memory.h"
-typedef PCIHostState PREPPCIState;
+typedef struct PRePPCIState {
+ PCIHostState host_state;
+ qemu_irq irq[4];
+} PREPPCIState;
+
+typedef struct RavenPCIState {
+ PCIDevice dev;
+} RavenPCIState;
static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
{
@@ -40,58 +47,24 @@ static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
return (addr & 0x7ff) | (i << 11);
}
-static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PREPPCIState *s = opaque;
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
-}
-
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PREPPCIState *s = opaque;
- val = bswap16(val);
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
-}
-
-static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
+static void ppc_pci_io_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned int size)
{
PREPPCIState *s = opaque;
- val = bswap32(val);
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
+ pci_data_write(s->host_state.bus, PPC_PCIIO_config(addr), val, size);
}
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
+static uint64_t ppc_pci_io_read(void *opaque, target_phys_addr_t addr,
+ unsigned int size)
{
PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
- return val;
-}
-
-static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
- val = bswap16(val);
- return val;
-}
-
-static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
- val = bswap32(val);
- return val;
+ return pci_data_read(s->host_state.bus, PPC_PCIIO_config(addr), size);
}
static const MemoryRegionOps PPC_PCIIO_ops = {
- .old_mmio = {
- .read = { PPC_PCIIO_readb, PPC_PCIIO_readw, PPC_PCIIO_readl, },
- .write = { PPC_PCIIO_writeb, PPC_PCIIO_writew, PPC_PCIIO_writel, },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .read = ppc_pci_io_read,
+ .write = ppc_pci_io_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
};
static int prep_map_irq(PCIDevice *pci_dev, int irq_num)
@@ -103,46 +76,107 @@ static void prep_set_irq(void *opaque, int irq_num, int level)
{
qemu_irq *pic = opaque;
- qemu_set_irq(pic[(irq_num & 1) ? 11 : 9] , level);
+ qemu_set_irq(pic[irq_num] , level);
}
-PCIBus *pci_prep_init(qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io)
+static int raven_pcihost_init(SysBusDevice *dev)
{
- PREPPCIState *s;
- PCIDevice *d;
+ PCIHostState *h = FROM_SYSBUS(PCIHostState, dev);
+ PREPPCIState *s = DO_UPCAST(PREPPCIState, host_state, h);
+ MemoryRegion *address_space_mem = get_system_memory();
+ MemoryRegion *address_space_io = get_system_io();
+ PCIBus *bus;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ sysbus_init_irq(dev, &s->irq[i]);
+ }
- s = g_malloc0(sizeof(PREPPCIState));
- s->bus = pci_register_bus(NULL, "pci",
- prep_set_irq, prep_map_irq, pic,
- address_space_mem,
- address_space_io,
- 0, 4);
+ bus = pci_register_bus(&h->busdev.qdev, NULL,
+ prep_set_irq, prep_map_irq, s->irq,
+ address_space_mem, address_space_io, 0, 4);
+ h->bus = bus;
- memory_region_init_io(&s->conf_mem, &pci_host_conf_be_ops, s,
+ memory_region_init_io(&h->conf_mem, &pci_host_conf_be_ops, s,
"pci-conf-idx", 1);
- memory_region_add_subregion(address_space_io, 0xcf8, &s->conf_mem);
- sysbus_init_ioports(&s->busdev, 0xcf8, 1);
+ sysbus_add_io(dev, 0xcf8, &h->conf_mem);
+ sysbus_init_ioports(&h->busdev, 0xcf8, 1);
- memory_region_init_io(&s->data_mem, &pci_host_data_be_ops, s,
+ memory_region_init_io(&h->data_mem, &pci_host_data_be_ops, s,
"pci-conf-data", 1);
- memory_region_add_subregion(address_space_io, 0xcfc, &s->data_mem);
- sysbus_init_ioports(&s->busdev, 0xcfc, 1);
-
- memory_region_init_io(&s->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
- memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg);
-
- /* PCI host bridge */
- d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
- sizeof(PCIDevice), 0, NULL, NULL);
- pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_MOTOROLA);
- pci_config_set_device_id(d->config, PCI_DEVICE_ID_MOTOROLA_RAVEN);
- d->config[0x08] = 0x00; // revision
- pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+ sysbus_add_io(dev, 0xcfc, &h->data_mem);
+ sysbus_init_ioports(&h->busdev, 0xcfc, 1);
+
+ memory_region_init_io(&h->mmcfg, &PPC_PCIIO_ops, s, "pciio", 0x00400000);
+ memory_region_add_subregion(address_space_mem, 0x80800000, &h->mmcfg);
+
+ pci_create_simple(bus, 0, "raven");
+
+ return 0;
+}
+
+static int raven_init(PCIDevice *d)
+{
d->config[0x0C] = 0x08; // cache_line_size
d->config[0x0D] = 0x10; // latency_timer
d->config[0x34] = 0x00; // capabilities_pointer
- return s->bus;
+ return 0;
+}
+
+static const VMStateDescription vmstate_raven = {
+ .name = "raven",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(dev, RavenPCIState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static void raven_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = raven_init;
+ k->vendor_id = PCI_VENDOR_ID_MOTOROLA;
+ k->device_id = PCI_DEVICE_ID_MOTOROLA_RAVEN;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+ dc->desc = "PReP Host Bridge - Motorola Raven";
+ dc->vmsd = &vmstate_raven;
+ dc->no_user = 1;
+}
+
+static TypeInfo raven_info = {
+ .name = "raven",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(RavenPCIState),
+ .class_init = raven_class_init,
+};
+
+static void raven_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = raven_pcihost_init;
+ dc->fw_name = "pci";
+ dc->no_user = 1;
}
+
+static TypeInfo raven_pcihost_info = {
+ .name = "raven-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PREPPCIState),
+ .class_init = raven_pcihost_class_init,
+};
+
+static void raven_register_devices(void)
+{
+ type_register_static(&raven_pcihost_info);
+ type_register_static(&raven_info);
+}
+
+device_init(raven_register_devices)
diff --git a/hw/prep_pci.h b/hw/prep_pci.h
deleted file mode 100644
index b6b481a517..0000000000
--- a/hw/prep_pci.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef QEMU_PREP_PCI_H
-#define QEMU_PREP_PCI_H
-
-#include "qemu-common.h"
-#include "memory.h"
-
-PCIBus *pci_prep_init(qemu_irq *pic,
- MemoryRegion *address_space_mem,
- MemoryRegion *address_space_io);
-
-#endif
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index 6ddd5005de..244c614510 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1233,17 +1233,26 @@ static const VMStateDescription vmstate_pxa2xx_rtc_regs = {
},
};
-static SysBusDeviceInfo pxa2xx_rtc_sysbus_info = {
- .init = pxa2xx_rtc_init,
- .qdev.name = "pxa2xx_rtc",
- .qdev.desc = "PXA2xx RTC Controller",
- .qdev.size = sizeof(PXA2xxRTCState),
- .qdev.vmsd = &vmstate_pxa2xx_rtc_regs,
+static void pxa2xx_rtc_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_rtc_init;
+ dc->desc = "PXA2xx RTC Controller";
+ dc->vmsd = &vmstate_pxa2xx_rtc_regs;
+}
+
+static TypeInfo pxa2xx_rtc_sysbus_info = {
+ .name = "pxa2xx_rtc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxRTCState),
+ .class_init = pxa2xx_rtc_sysbus_class_init,
};
/* I2C Interface */
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
PXA2xxI2CState *host;
} PXA2xxI2CSlaveState;
@@ -1279,7 +1288,7 @@ static void pxa2xx_i2c_update(PXA2xxI2CState *s)
}
/* These are only stubs now. */
-static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+static void pxa2xx_i2c_event(I2CSlave *i2c, enum i2c_event event)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
@@ -1303,7 +1312,7 @@ static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
pxa2xx_i2c_update(s);
}
-static int pxa2xx_i2c_rx(i2c_slave *i2c)
+static int pxa2xx_i2c_rx(I2CSlave *i2c)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
@@ -1318,7 +1327,7 @@ static int pxa2xx_i2c_rx(i2c_slave *i2c)
return s->data;
}
-static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+static int pxa2xx_i2c_tx(I2CSlave *i2c, uint8_t data)
{
PXA2xxI2CSlaveState *slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, i2c);
PXA2xxI2CState *s = slave->host;
@@ -1466,19 +1475,27 @@ static const VMStateDescription vmstate_pxa2xx_i2c = {
}
};
-static int pxa2xx_i2c_slave_init(i2c_slave *i2c)
+static int pxa2xx_i2c_slave_init(I2CSlave *i2c)
{
/* Nothing to do. */
return 0;
}
-static I2CSlaveInfo pxa2xx_i2c_slave_info = {
- .qdev.name = "pxa2xx-i2c-slave",
- .qdev.size = sizeof(PXA2xxI2CSlaveState),
- .init = pxa2xx_i2c_slave_init,
- .event = pxa2xx_i2c_event,
- .recv = pxa2xx_i2c_rx,
- .send = pxa2xx_i2c_tx
+static void pxa2xx_i2c_slave_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = pxa2xx_i2c_slave_init;
+ k->event = pxa2xx_i2c_event;
+ k->recv = pxa2xx_i2c_rx;
+ k->send = pxa2xx_i2c_tx;
+}
+
+static TypeInfo pxa2xx_i2c_slave_info = {
+ .name = "pxa2xx-i2c-slave",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(PXA2xxI2CSlaveState),
+ .class_init = pxa2xx_i2c_slave_class_init,
};
PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base,
@@ -1526,17 +1543,28 @@ i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
return s->bus;
}
-static SysBusDeviceInfo pxa2xx_i2c_info = {
- .init = pxa2xx_i2c_initfn,
- .qdev.name = "pxa2xx_i2c",
- .qdev.desc = "PXA2xx I2C Bus Controller",
- .qdev.size = sizeof(PXA2xxI2CState),
- .qdev.vmsd = &vmstate_pxa2xx_i2c,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
- DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pxa2xx_i2c_properties[] = {
+ DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000),
+ DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_i2c_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_i2c_initfn;
+ dc->desc = "PXA2xx I2C Bus Controller";
+ dc->vmsd = &vmstate_pxa2xx_i2c;
+ dc->props = pxa2xx_i2c_properties;
+}
+
+static TypeInfo pxa2xx_i2c_info = {
+ .name = "pxa2xx_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxI2CState),
+ .class_init = pxa2xx_i2c_class_init,
};
/* PXA Inter-IC Sound Controller */
@@ -2288,12 +2316,26 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size)
return s;
}
+static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pxa2xx_ssp_init;
+}
+
+static TypeInfo pxa2xx_ssp_info = {
+ .name = "pxa2xx-ssp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxSSPState),
+ .class_init = pxa2xx_ssp_class_init,
+};
+
static void pxa2xx_register_devices(void)
{
- i2c_register_slave(&pxa2xx_i2c_slave_info);
- sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init);
- sysbus_register_withprop(&pxa2xx_i2c_info);
- sysbus_register_withprop(&pxa2xx_rtc_sysbus_info);
+ type_register_static(&pxa2xx_i2c_slave_info);
+ type_register_static(&pxa2xx_ssp_info);
+ type_register_static(&pxa2xx_i2c_info);
+ type_register_static(&pxa2xx_rtc_sysbus_info);
}
device_init(pxa2xx_register_devices)
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
index cb281071f0..2d61565f1d 100644
--- a/hw/pxa2xx_dma.c
+++ b/hw/pxa2xx_dma.c
@@ -543,20 +543,31 @@ static VMStateDescription vmstate_pxa2xx_dma = {
},
};
-static SysBusDeviceInfo pxa2xx_dma_info = {
- .init = pxa2xx_dma_init,
- .qdev.name = "pxa2xx-dma",
- .qdev.desc = "PXA2xx DMA controller",
- .qdev.size = sizeof(PXA2xxDMAState),
- .qdev.vmsd = &vmstate_pxa2xx_dma,
- .qdev.props = (Property[]) {
- DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pxa2xx_dma_properties[] = {
+ DEFINE_PROP_INT32("channels", PXA2xxDMAState, channels, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_dma_init;
+ dc->desc = "PXA2xx DMA controller";
+ dc->vmsd = &vmstate_pxa2xx_dma;
+ dc->props = pxa2xx_dma_properties;
+}
+
+static TypeInfo pxa2xx_dma_info = {
+ .name = "pxa2xx-dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxDMAState),
+ .class_init = pxa2xx_dma_class_init,
};
static void pxa2xx_dma_register(void)
{
- sysbus_register_withprop(&pxa2xx_dma_info);
+ type_register_static(&pxa2xx_dma_info);
}
device_init(pxa2xx_dma_register);
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
index cc58c40914..67fd17c4ca 100644
--- a/hw/pxa2xx_gpio.c
+++ b/hw/pxa2xx_gpio.c
@@ -317,20 +317,31 @@ static const VMStateDescription vmstate_pxa2xx_gpio_regs = {
},
};
-static SysBusDeviceInfo pxa2xx_gpio_info = {
- .init = pxa2xx_gpio_initfn,
- .qdev.name = "pxa2xx-gpio",
- .qdev.desc = "PXA2xx GPIO controller",
- .qdev.size = sizeof(PXA2xxGPIOInfo),
- .qdev.props = (Property []) {
- DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
- DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property pxa2xx_gpio_properties[] = {
+ DEFINE_PROP_INT32("lines", PXA2xxGPIOInfo, lines, 0),
+ DEFINE_PROP_INT32("ncpu", PXA2xxGPIOInfo, ncpu, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa2xx_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_gpio_initfn;
+ dc->desc = "PXA2xx GPIO controller";
+ dc->props = pxa2xx_gpio_properties;
+}
+
+static TypeInfo pxa2xx_gpio_info = {
+ .name = "pxa2xx-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxGPIOInfo),
+ .class_init = pxa2xx_gpio_class_init,
};
static void pxa2xx_gpio_register(void)
{
- sysbus_register_withprop(&pxa2xx_gpio_info);
+ type_register_static(&pxa2xx_gpio_info);
}
device_init(pxa2xx_gpio_register);
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
index 92effbc806..ca85743aea 100644
--- a/hw/pxa2xx_pic.c
+++ b/hw/pxa2xx_pic.c
@@ -296,16 +296,25 @@ static int pxa2xx_pic_initfn(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo pxa2xx_pic_info = {
- .init = pxa2xx_pic_initfn,
- .qdev.name = "pxa2xx_pic",
- .qdev.desc = "PXA2xx PIC",
- .qdev.size = sizeof(PXA2xxPICState),
- .qdev.vmsd = &vmstate_pxa2xx_pic_regs,
+static void pxa2xx_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_pic_initfn;
+ dc->desc = "PXA2xx PIC";
+ dc->vmsd = &vmstate_pxa2xx_pic_regs;
+}
+
+static TypeInfo pxa2xx_pic_info = {
+ .name = "pxa2xx_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxPICState),
+ .class_init = pxa2xx_pic_class_init,
};
static void pxa2xx_pic_register(void)
{
- sysbus_register_withprop(&pxa2xx_pic_info);
+ type_register_static(&pxa2xx_pic_info);
}
device_init(pxa2xx_pic_register);
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
index 50e26789d2..90800751b1 100644
--- a/hw/pxa2xx_timer.c
+++ b/hw/pxa2xx_timer.c
@@ -477,37 +477,59 @@ static const VMStateDescription vmstate_pxa2xx_timer_regs = {
}
};
-static SysBusDeviceInfo pxa25x_timer_dev_info = {
- .init = pxa2xx_timer_init,
- .qdev.name = "pxa25x-timer",
- .qdev.desc = "PXA25x timer",
- .qdev.size = sizeof(PXA2xxTimerInfo),
- .qdev.vmsd = &vmstate_pxa2xx_timer_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property pxa25x_timer_dev_properties[] = {
+ DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
+ DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+ PXA2XX_TIMER_HAVE_TM4, false),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo pxa27x_timer_dev_info = {
- .init = pxa2xx_timer_init,
- .qdev.name = "pxa27x-timer",
- .qdev.desc = "PXA27x timer",
- .qdev.size = sizeof(PXA2xxTimerInfo),
- .qdev.vmsd = &vmstate_pxa2xx_timer_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
- DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
- PXA2XX_TIMER_HAVE_TM4, true),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_timer_init;
+ dc->desc = "PXA25x timer";
+ dc->vmsd = &vmstate_pxa2xx_timer_regs;
+ dc->props = pxa25x_timer_dev_properties;
+}
+
+static TypeInfo pxa25x_timer_dev_info = {
+ .name = "pxa25x-timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxTimerInfo),
+ .class_init = pxa25x_timer_dev_class_init,
+};
+
+static Property pxa27x_timer_dev_properties[] = {
+ DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+ DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+ PXA2XX_TIMER_HAVE_TM4, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void pxa27x_timer_dev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = pxa2xx_timer_init;
+ dc->desc = "PXA27x timer";
+ dc->vmsd = &vmstate_pxa2xx_timer_regs;
+ dc->props = pxa27x_timer_dev_properties;
+}
+
+static TypeInfo pxa27x_timer_dev_info = {
+ .name = "pxa27x-timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PXA2xxTimerInfo),
+ .class_init = pxa27x_timer_dev_class_init,
};
static void pxa2xx_timer_register(void)
{
- sysbus_register_withprop(&pxa25x_timer_dev_info);
- sysbus_register_withprop(&pxa27x_timer_dev_info);
+ type_register_static(&pxa25x_timer_dev_info);
+ type_register_static(&pxa27x_timer_dev_info);
};
device_init(pxa2xx_timer_register);
diff --git a/hw/qdev-addr.c b/hw/qdev-addr.c
index 5ddda2d0f4..5976dcdf47 100644
--- a/hw/qdev-addr.c
+++ b/hw/qdev-addr.c
@@ -18,9 +18,10 @@ static int print_taddr(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, "0x" TARGET_FMT_plx, *ptr);
}
-static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
+static void get_taddr(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -29,9 +30,10 @@ static void get_taddr(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
-static void set_taddr(DeviceState *dev, Visitor *v, void *opaque,
+static void set_taddr(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
target_phys_addr_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
diff --git a/hw/qdev-monitor.c b/hw/qdev-monitor.c
new file mode 100644
index 0000000000..135c2bf237
--- /dev/null
+++ b/hw/qdev-monitor.c
@@ -0,0 +1,588 @@
+/*
+ * Dynamic device configuration and creation.
+ *
+ * Copyright (c) 2009 CodeSourcery
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qdev.h"
+#include "monitor.h"
+
+/*
+ * Aliases were a bad idea from the start. Let's keep them
+ * from spreading further.
+ */
+typedef struct QDevAlias
+{
+ const char *typename;
+ const char *alias;
+} QDevAlias;
+
+static const QDevAlias qdev_alias_table[] = {
+ { "virtio-blk-pci", "virtio-blk" },
+ { "virtio-net-pci", "virtio-net" },
+ { "virtio-serial-pci", "virtio-serial" },
+ { "virtio-balloon-pci", "virtio-balloon" },
+ { "virtio-blk-s390", "virtio-blk" },
+ { "virtio-net-s390", "virtio-net" },
+ { "virtio-serial-s390", "virtio-serial" },
+ { "lsi53c895a", "lsi" },
+ { "ich9-ahci", "ahci" },
+ { }
+};
+
+static const char *qdev_class_get_alias(DeviceClass *dc)
+{
+ const char *typename = object_class_get_name(OBJECT_CLASS(dc));
+ int i;
+
+ for (i = 0; qdev_alias_table[i].typename; i++) {
+ if (strcmp(qdev_alias_table[i].typename, typename) == 0) {
+ return qdev_alias_table[i].alias;
+ }
+ }
+
+ return NULL;
+}
+
+static bool qdev_class_has_alias(DeviceClass *dc)
+{
+ return (qdev_class_get_alias(dc) != NULL);
+}
+
+static void qdev_print_devinfo(ObjectClass *klass, void *opaque)
+{
+ DeviceClass *dc;
+ bool *show_no_user = opaque;
+
+ dc = (DeviceClass *)object_class_dynamic_cast(klass, TYPE_DEVICE);
+
+ if (!dc || (show_no_user && !*show_no_user && dc->no_user)) {
+ return;
+ }
+
+ error_printf("name \"%s\"", object_class_get_name(klass));
+ if (dc->bus_info) {
+ error_printf(", bus %s", dc->bus_info->name);
+ }
+ if (qdev_class_has_alias(dc)) {
+ error_printf(", alias \"%s\"", qdev_class_get_alias(dc));
+ }
+ if (dc->desc) {
+ error_printf(", desc \"%s\"", dc->desc);
+ }
+ if (dc->no_user) {
+ error_printf(", no-user");
+ }
+ error_printf("\n");
+}
+
+static int set_property(const char *name, const char *value, void *opaque)
+{
+ DeviceState *dev = opaque;
+
+ if (strcmp(name, "driver") == 0)
+ return 0;
+ if (strcmp(name, "bus") == 0)
+ return 0;
+
+ if (qdev_prop_parse(dev, name, value) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+static const char *find_typename_by_alias(const char *alias)
+{
+ int i;
+
+ for (i = 0; qdev_alias_table[i].alias; i++) {
+ if (strcmp(qdev_alias_table[i].alias, alias) == 0) {
+ return qdev_alias_table[i].typename;
+ }
+ }
+
+ return NULL;
+}
+
+int qdev_device_help(QemuOpts *opts)
+{
+ const char *driver;
+ Property *prop;
+ ObjectClass *klass;
+ DeviceClass *info;
+
+ driver = qemu_opt_get(opts, "driver");
+ if (driver && !strcmp(driver, "?")) {
+ bool show_no_user = false;
+ object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, &show_no_user);
+ return 1;
+ }
+
+ if (!driver || !qemu_opt_get(opts, "?")) {
+ return 0;
+ }
+
+ klass = object_class_by_name(driver);
+ if (!klass) {
+ const char *typename = find_typename_by_alias(driver);
+
+ if (typename) {
+ driver = typename;
+ klass = object_class_by_name(driver);
+ }
+ }
+
+ if (!klass) {
+ return 0;
+ }
+ info = DEVICE_CLASS(klass);
+
+ for (prop = info->props; prop && prop->name; prop++) {
+ /*
+ * TODO Properties without a parser are just for dirty hacks.
+ * qdev_prop_ptr is the only such PropertyInfo. It's marked
+ * for removal. This conditional should be removed along with
+ * it.
+ */
+ if (!prop->info->parse) {
+ continue; /* no way to set it, don't show */
+ }
+ error_printf("%s.%s=%s\n", driver, prop->name,
+ prop->info->legacy_name ?: prop->info->name);
+ }
+ if (info->bus_info) {
+ for (prop = info->bus_info->props; prop && prop->name; prop++) {
+ if (!prop->info->parse) {
+ continue; /* no way to set it, don't show */
+ }
+ error_printf("%s.%s=%s\n", driver, prop->name,
+ prop->info->legacy_name ?: prop->info->name);
+ }
+ }
+ return 1;
+}
+
+static Object *qdev_get_peripheral(void)
+{
+ static Object *dev;
+
+ if (dev == NULL) {
+ dev = object_new("container");
+ object_property_add_child(object_get_root(), "peripheral",
+ OBJECT(dev), NULL);
+ }
+
+ return dev;
+}
+
+static Object *qdev_get_peripheral_anon(void)
+{
+ static Object *dev;
+
+ if (dev == NULL) {
+ dev = object_new("container");
+ object_property_add_child(object_get_root(), "peripheral-anon",
+ OBJECT(dev), NULL);
+ }
+
+ return dev;
+}
+
+static void qbus_list_bus(DeviceState *dev)
+{
+ BusState *child;
+ const char *sep = " ";
+
+ error_printf("child busses at \"%s\":",
+ dev->id ? dev->id : object_get_typename(OBJECT(dev)));
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ error_printf("%s\"%s\"", sep, child->name);
+ sep = ", ";
+ }
+ error_printf("\n");
+}
+
+static void qbus_list_dev(BusState *bus)
+{
+ DeviceState *dev;
+ const char *sep = " ";
+
+ error_printf("devices at \"%s\":", bus->name);
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev)));
+ if (dev->id)
+ error_printf("/\"%s\"", dev->id);
+ sep = ", ";
+ }
+ error_printf("\n");
+}
+
+static BusState *qbus_find_bus(DeviceState *dev, char *elem)
+{
+ BusState *child;
+
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ if (strcmp(child->name, elem) == 0) {
+ return child;
+ }
+ }
+ return NULL;
+}
+
+static DeviceState *qbus_find_dev(BusState *bus, char *elem)
+{
+ DeviceState *dev;
+
+ /*
+ * try to match in order:
+ * (1) instance id, if present
+ * (2) driver name
+ * (3) driver alias, if present
+ */
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ if (dev->id && strcmp(dev->id, elem) == 0) {
+ return dev;
+ }
+ }
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) {
+ return dev;
+ }
+ }
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ if (qdev_class_has_alias(dc) &&
+ strcmp(qdev_class_get_alias(dc), elem) == 0) {
+ return dev;
+ }
+ }
+ return NULL;
+}
+
+static BusState *qbus_find_recursive(BusState *bus, const char *name,
+ const BusInfo *info)
+{
+ DeviceState *dev;
+ BusState *child, *ret;
+ int match = 1;
+
+ if (name && (strcmp(bus->name, name) != 0)) {
+ match = 0;
+ }
+ if (info && (bus->info != info)) {
+ match = 0;
+ }
+ if (match) {
+ return bus;
+ }
+
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ ret = qbus_find_recursive(child, name, info);
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+ return NULL;
+}
+
+static BusState *qbus_find(const char *path)
+{
+ DeviceState *dev;
+ BusState *bus;
+ char elem[128];
+ int pos, len;
+
+ /* find start element */
+ if (path[0] == '/') {
+ bus = sysbus_get_default();
+ pos = 0;
+ } else {
+ if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
+ assert(!path[0]);
+ elem[0] = len = 0;
+ }
+ bus = qbus_find_recursive(sysbus_get_default(), elem, NULL);
+ if (!bus) {
+ qerror_report(QERR_BUS_NOT_FOUND, elem);
+ return NULL;
+ }
+ pos = len;
+ }
+
+ for (;;) {
+ assert(path[pos] == '/' || !path[pos]);
+ while (path[pos] == '/') {
+ pos++;
+ }
+ if (path[pos] == '\0') {
+ return bus;
+ }
+
+ /* find device */
+ if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
+ assert(0);
+ elem[0] = len = 0;
+ }
+ pos += len;
+ dev = qbus_find_dev(bus, elem);
+ if (!dev) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, elem);
+ if (!monitor_cur_is_qmp()) {
+ qbus_list_dev(bus);
+ }
+ return NULL;
+ }
+
+ assert(path[pos] == '/' || !path[pos]);
+ while (path[pos] == '/') {
+ pos++;
+ }
+ if (path[pos] == '\0') {
+ /* last specified element is a device. If it has exactly
+ * one child bus accept it nevertheless */
+ switch (dev->num_child_bus) {
+ case 0:
+ qerror_report(QERR_DEVICE_NO_BUS, elem);
+ return NULL;
+ case 1:
+ return QLIST_FIRST(&dev->child_bus);
+ default:
+ qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
+ if (!monitor_cur_is_qmp()) {
+ qbus_list_bus(dev);
+ }
+ return NULL;
+ }
+ }
+
+ /* find bus */
+ if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
+ assert(0);
+ elem[0] = len = 0;
+ }
+ pos += len;
+ bus = qbus_find_bus(dev, elem);
+ if (!bus) {
+ qerror_report(QERR_BUS_NOT_FOUND, elem);
+ if (!monitor_cur_is_qmp()) {
+ qbus_list_bus(dev);
+ }
+ return NULL;
+ }
+ }
+}
+
+DeviceState *qdev_device_add(QemuOpts *opts)
+{
+ ObjectClass *obj;
+ DeviceClass *k;
+ const char *driver, *path, *id;
+ DeviceState *qdev;
+ BusState *bus;
+
+ driver = qemu_opt_get(opts, "driver");
+ if (!driver) {
+ qerror_report(QERR_MISSING_PARAMETER, "driver");
+ return NULL;
+ }
+
+ /* find driver */
+ obj = object_class_by_name(driver);
+ if (!obj) {
+ const char *typename = find_typename_by_alias(driver);
+
+ if (typename) {
+ driver = typename;
+ obj = object_class_by_name(driver);
+ }
+ }
+
+ if (!obj) {
+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "device type");
+ return NULL;
+ }
+
+ k = DEVICE_CLASS(obj);
+
+ /* find bus */
+ path = qemu_opt_get(opts, "bus");
+ if (path != NULL) {
+ bus = qbus_find(path);
+ if (!bus) {
+ return NULL;
+ }
+ if (bus->info != k->bus_info) {
+ qerror_report(QERR_BAD_BUS_FOR_DEVICE,
+ driver, bus->info->name);
+ return NULL;
+ }
+ } else {
+ bus = qbus_find_recursive(sysbus_get_default(), NULL, k->bus_info);
+ if (!bus) {
+ qerror_report(QERR_NO_BUS_FOR_DEVICE,
+ driver, k->bus_info->name);
+ return NULL;
+ }
+ }
+ if (qdev_hotplug && !bus->allow_hotplug) {
+ qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
+ return NULL;
+ }
+
+ if (!bus) {
+ bus = sysbus_get_default();
+ }
+
+ /* create device, set properties */
+ qdev = DEVICE(object_new(driver));
+ qdev_set_parent_bus(qdev, bus);
+ qdev_prop_set_globals(qdev);
+
+ id = qemu_opts_id(opts);
+ if (id) {
+ qdev->id = id;
+ object_property_add_child(qdev_get_peripheral(), qdev->id,
+ OBJECT(qdev), NULL);
+ } else {
+ static int anon_count;
+ gchar *name = g_strdup_printf("device[%d]", anon_count++);
+ object_property_add_child(qdev_get_peripheral_anon(), name,
+ OBJECT(qdev), NULL);
+ g_free(name);
+ }
+ if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
+ qdev_free(qdev);
+ return NULL;
+ }
+ if (qdev_init(qdev) < 0) {
+ qerror_report(QERR_DEVICE_INIT_FAILED, driver);
+ return NULL;
+ }
+ qdev->opts = opts;
+ return qdev;
+}
+
+
+#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
+static void qbus_print(Monitor *mon, BusState *bus, int indent);
+
+static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
+ const char *prefix, int indent)
+{
+ char buf[64];
+
+ if (!props)
+ return;
+ while (props->name) {
+ /*
+ * TODO Properties without a print method are just for dirty
+ * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
+ * marked for removal. The test props->info->print should be
+ * removed along with it.
+ */
+ if (props->info->print) {
+ props->info->print(dev, props, buf, sizeof(buf));
+ qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
+ }
+ props++;
+ }
+}
+
+static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+ BusState *child;
+ qdev_printf("dev: %s, id \"%s\"\n", object_get_typename(OBJECT(dev)),
+ dev->id ? dev->id : "");
+ indent += 2;
+ if (dev->num_gpio_in) {
+ qdev_printf("gpio-in %d\n", dev->num_gpio_in);
+ }
+ if (dev->num_gpio_out) {
+ qdev_printf("gpio-out %d\n", dev->num_gpio_out);
+ }
+ qdev_print_props(mon, dev, qdev_get_props(dev), "dev", indent);
+ qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
+ if (dev->parent_bus->info->print_dev)
+ dev->parent_bus->info->print_dev(mon, dev, indent);
+ QLIST_FOREACH(child, &dev->child_bus, sibling) {
+ qbus_print(mon, child, indent);
+ }
+}
+
+static void qbus_print(Monitor *mon, BusState *bus, int indent)
+{
+ struct DeviceState *dev;
+
+ qdev_printf("bus: %s\n", bus->name);
+ indent += 2;
+ qdev_printf("type %s\n", bus->info->name);
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
+ qdev_print(mon, dev, indent);
+ }
+}
+#undef qdev_printf
+
+void do_info_qtree(Monitor *mon)
+{
+ if (sysbus_get_default())
+ qbus_print(mon, sysbus_get_default(), 0);
+}
+
+void do_info_qdm(Monitor *mon)
+{
+ object_class_foreach(qdev_print_devinfo, TYPE_DEVICE, false, NULL);
+}
+
+int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ QemuOpts *opts;
+
+ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
+ if (!opts) {
+ return -1;
+ }
+ if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
+ qemu_opts_del(opts);
+ return 0;
+ }
+ if (!qdev_device_add(opts)) {
+ qemu_opts_del(opts);
+ return -1;
+ }
+ return 0;
+}
+
+int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+ const char *id = qdict_get_str(qdict, "id");
+ DeviceState *dev;
+
+ dev = qdev_find_recursive(sysbus_get_default(), id);
+ if (NULL == dev) {
+ qerror_report(QERR_DEVICE_NOT_FOUND, id);
+ return -1;
+ }
+ return qdev_unplug(dev);
+}
+
+void qdev_machine_init(void)
+{
+ qdev_get_peripheral_anon();
+ qdev_get_peripheral();
+}
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 02f0dae0bc..c4583a14d7 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -40,9 +40,9 @@ static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src)
/* Bit */
static int parse_bit(DeviceState *dev, Property *prop, const char *str)
{
- if (!strncasecmp(str, "on", 2))
+ if (!strcasecmp(str, "on"))
bit_prop_set(dev, prop, true);
- else if (!strncasecmp(str, "off", 3))
+ else if (!strcasecmp(str, "off"))
bit_prop_set(dev, prop, false);
else
return -EINVAL;
@@ -55,9 +55,10 @@ static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
}
-static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
+static void get_bit(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *p = qdev_get_prop_ptr(dev, prop);
bool value = (*p & qdev_get_prop_mask(prop)) != 0;
@@ -65,9 +66,10 @@ static void get_bit(DeviceState *dev, Visitor *v, void *opaque,
visit_type_bool(v, &value, name, errp);
}
-static void set_bit(DeviceState *dev, Visitor *v, void *opaque,
+static void set_bit(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
bool value;
@@ -118,9 +120,10 @@ static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len)
return snprintf(dest, len, "%" PRIu8, *ptr);
}
-static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int8(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -129,9 +132,10 @@ static void get_int8(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
-static void set_int8(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
+static void set_int8(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int8_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -224,9 +228,10 @@ static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu16, *ptr);
}
-static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int16(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -235,9 +240,10 @@ static void get_int16(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
-static void set_int16(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int16(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int16_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -296,9 +302,10 @@ static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu32, *ptr);
}
-static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int32(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
int64_t value;
@@ -307,9 +314,10 @@ static void get_int32(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &value, name, errp);
}
-static void set_int32(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int32(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -433,18 +441,20 @@ static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "%" PRIu64, *ptr);
}
-static void get_int64(DeviceState *dev, Visitor *v, void *opaque,
+static void get_int64(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
visit_type_int(v, ptr, name, errp);
}
-static void set_int64(DeviceState *dev, Visitor *v, void *opaque,
+static void set_int64(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int64_t *ptr = qdev_get_prop_ptr(dev, prop);
@@ -523,9 +533,10 @@ static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len
return snprintf(dest, len, "\"%s\"", *ptr);
}
-static void get_string(DeviceState *dev, Visitor *v, void *opaque,
+static void get_string(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
@@ -537,9 +548,10 @@ static void get_string(DeviceState *dev, Visitor *v, void *opaque,
}
}
-static void set_string(DeviceState *dev, Visitor *v, void *opaque,
+static void set_string(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -609,9 +621,10 @@ static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len)
*ptr ? bdrv_get_device_name(*ptr) : "<null>");
}
-static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
+static void get_generic(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
void **ptr = qdev_get_prop_ptr(dev, prop);
char buffer[1024];
@@ -624,9 +637,10 @@ static void get_generic(DeviceState *dev, Visitor *v, void *opaque,
visit_type_str(v, &p, name, errp);
}
-static void set_generic(DeviceState *dev, Visitor *v, void *opaque,
+static void set_generic(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
char *str;
@@ -774,9 +788,10 @@ static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len)
}
}
-static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
+static void get_vlan(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
int64_t id;
@@ -785,9 +800,10 @@ static void get_vlan(DeviceState *dev, Visitor *v, void *opaque,
visit_type_int(v, &id, name, errp);
}
-static void set_vlan(DeviceState *dev, Visitor *v, void *opaque,
+static void set_vlan(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
VLANState **ptr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
@@ -885,6 +901,55 @@ PropertyInfo qdev_prop_macaddr = {
.set = set_generic,
};
+
+/* --- lost tick policy --- */
+
+static const struct {
+ const char *name;
+ LostTickPolicy code;
+} lost_tick_policy_table[] = {
+ { .name = "discard", .code = LOST_TICK_DISCARD },
+ { .name = "delay", .code = LOST_TICK_DELAY },
+ { .name = "merge", .code = LOST_TICK_MERGE },
+ { .name = "slew", .code = LOST_TICK_SLEW },
+};
+
+static int parse_lost_tick_policy(DeviceState *dev, Property *prop,
+ const char *str)
+{
+ LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lost_tick_policy_table); i++) {
+ if (!strcasecmp(str, lost_tick_policy_table[i].name)) {
+ *ptr = lost_tick_policy_table[i].code;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(lost_tick_policy_table)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int print_lost_tick_policy(DeviceState *dev, Property *prop, char *dest,
+ size_t len)
+{
+ LostTickPolicy *ptr = qdev_get_prop_ptr(dev, prop);
+
+ return snprintf(dest, len, "%s", lost_tick_policy_table[*ptr].name);
+}
+
+PropertyInfo qdev_prop_losttickpolicy = {
+ .name = "lost_tick_policy",
+ .type = PROP_TYPE_LOSTTICKPOLICY,
+ .size = sizeof(LostTickPolicy),
+ .parse = parse_lost_tick_policy,
+ .print = print_lost_tick_policy,
+ .get = get_generic,
+ .set = set_generic,
+};
+
/* --- pci address --- */
/*
@@ -922,9 +987,10 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t
}
}
-static void get_pci_devfn(DeviceState *dev, Visitor *v, void *opaque,
+static void get_pci_devfn(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
char buffer[32];
@@ -966,7 +1032,7 @@ static Property *qdev_prop_find(DeviceState *dev, const char *name)
Property *prop;
/* device properties */
- prop = qdev_prop_walk(dev->info->props, name);
+ prop = qdev_prop_walk(qdev_get_props(dev), name);
if (prop)
return prop;
@@ -989,16 +1055,16 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
switch (ret) {
case -EEXIST:
error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
- dev->info->name, prop->name, value);
+ object_get_typename(OBJECT(dev)), prop->name, value);
break;
default:
case -EINVAL:
error_set(errp, QERR_PROPERTY_VALUE_BAD,
- dev->info->name, prop->name, value);
+ object_get_typename(OBJECT(dev)), prop->name, value);
break;
case -ENOENT:
error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
- dev->info->name, prop->name, value);
+ object_get_typename(OBJECT(dev)), prop->name, value);
break;
case 0:
break;
@@ -1018,7 +1084,7 @@ int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
* removed along with it.
*/
if (!prop || !prop->info->parse) {
- qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name);
+ qerror_report(QERR_PROPERTY_NOT_FOUND, object_get_typename(OBJECT(dev)), name);
return -1;
}
ret = prop->info->parse(dev, prop, value);
@@ -1039,12 +1105,12 @@ void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyT
prop = qdev_prop_find(dev, name);
if (!prop) {
fprintf(stderr, "%s: property \"%s.%s\" not found\n",
- __FUNCTION__, dev->info->name, name);
+ __FUNCTION__, object_get_typename(OBJECT(dev)), name);
abort();
}
if (prop->info->type != type) {
fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n",
- __FUNCTION__, dev->info->name, name);
+ __FUNCTION__, object_get_typename(OBJECT(dev)), name);
abort();
}
qdev_prop_cpy(dev, prop, src);
@@ -1093,7 +1159,7 @@ int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *va
if (res < 0) {
error_report("Can't attach drive %s to %s.%s: %s",
bdrv_get_device_name(value),
- dev->id ? dev->id : dev->info->name,
+ dev->id ? dev->id : object_get_typename(OBJECT(dev)),
name, strerror(-res));
return -1;
}
@@ -1127,6 +1193,12 @@ void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR);
}
+void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
+ LostTickPolicy *value)
+{
+ qdev_prop_set(dev, name, value, PROP_TYPE_LOSTTICKPOLICY);
+}
+
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
qdev_prop_set(dev, name, &value, PROP_TYPE_PTR);
@@ -1165,8 +1237,8 @@ void qdev_prop_set_globals(DeviceState *dev)
GlobalProperty *prop;
QTAILQ_FOREACH(prop, &global_props, next) {
- if (strcmp(dev->info->name, prop->driver) != 0 &&
- strcmp(dev->info->bus_info->name, prop->driver) != 0) {
+ if (strcmp(object_get_typename(OBJECT(dev)), prop->driver) != 0 &&
+ strcmp(qdev_get_bus_info(dev)->name, prop->driver) != 0) {
continue;
}
if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
diff --git a/hw/qdev.c b/hw/qdev.c
index e59f3455d7..e3b53b7f62 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -28,9 +28,8 @@
#include "net.h"
#include "qdev.h"
#include "sysemu.h"
-#include "monitor.h"
-static int qdev_hotplug = 0;
+int qdev_hotplug = 0;
static bool qdev_hot_added = false;
static bool qdev_hot_removed = false;
@@ -38,86 +37,60 @@ static bool qdev_hot_removed = false;
static BusState *main_system_bus;
static void main_system_bus_create(void);
-DeviceInfo *device_info_list;
-
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info);
-static BusState *qbus_find(const char *path);
-
/* Register a new device type. */
-void qdev_register(DeviceInfo *info)
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->vmsd;
+}
+
+BusInfo *qdev_get_bus_info(DeviceState *dev)
{
- assert(info->size >= sizeof(DeviceState));
- assert(!info->next);
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->bus_info;
+}
- info->next = device_info_list;
- device_info_list = info;
+Property *qdev_get_props(DeviceState *dev)
+{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+ return dc->props;
}
-static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name)
+const char *qdev_fw_name(DeviceState *dev)
{
- DeviceInfo *info;
-
- /* first check device names */
- for (info = device_info_list; info != NULL; info = info->next) {
- if (bus_info && info->bus_info != bus_info)
- continue;
- if (strcmp(info->name, name) != 0)
- continue;
- return info;
- }
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
- /* failing that check the aliases */
- for (info = device_info_list; info != NULL; info = info->next) {
- if (bus_info && info->bus_info != bus_info)
- continue;
- if (!info->alias)
- continue;
- if (strcmp(info->alias, name) != 0)
- continue;
- return info;
+ if (dc->fw_name) {
+ return dc->fw_name;
}
- return NULL;
+
+ return object_get_typename(OBJECT(dev));
+}
+
+bool qdev_exists(const char *name)
+{
+ return !!object_class_by_name(name);
}
static void qdev_property_add_legacy(DeviceState *dev, Property *prop,
Error **errp);
-static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
- DeviceState *dev;
Property *prop;
- assert(bus->info == info->bus_info);
- dev = g_malloc0(info->size);
- dev->info = info;
- dev->parent_bus = bus;
- qdev_prop_set_defaults(dev, dev->info->props);
- qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
- qdev_prop_set_globals(dev);
- QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
if (qdev_hotplug) {
assert(bus->allow_hotplug);
- dev->hotplugged = 1;
- qdev_hot_added = true;
}
- dev->instance_id_alias = -1;
- QTAILQ_INIT(&dev->properties);
- dev->state = DEV_STATE_CREATED;
- for (prop = dev->info->props; prop && prop->name; prop++) {
- qdev_property_add_legacy(dev, prop, NULL);
- qdev_property_add_static(dev, prop, NULL);
- }
+ dev->parent_bus = bus;
+ QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
- for (prop = dev->info->bus_info->props; prop && prop->name; prop++) {
+ qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
+ for (prop = qdev_get_bus_info(dev)->props; prop && prop->name; prop++) {
qdev_property_add_legacy(dev, prop, NULL);
qdev_property_add_static(dev, prop, NULL);
}
-
- qdev_property_add_str(dev, "type", qdev_get_type, NULL, NULL);
-
- return dev;
}
/* Create a new device. This only initializes the device state structure
@@ -142,197 +115,23 @@ DeviceState *qdev_create(BusState *bus, const char *name)
DeviceState *qdev_try_create(BusState *bus, const char *name)
{
- DeviceInfo *info;
-
- if (!bus) {
- bus = sysbus_get_default();
- }
+ DeviceState *dev;
- info = qdev_find_info(bus->info, name);
- if (!info) {
+ dev = DEVICE(object_new(name));
+ if (!dev) {
return NULL;
}
- return qdev_create_from_info(bus, info);
-}
-
-static void qdev_print_devinfo(DeviceInfo *info)
-{
- error_printf("name \"%s\", bus %s",
- info->name, info->bus_info->name);
- if (info->alias) {
- error_printf(", alias \"%s\"", info->alias);
- }
- if (info->desc) {
- error_printf(", desc \"%s\"", info->desc);
- }
- if (info->no_user) {
- error_printf(", no-user");
- }
- error_printf("\n");
-}
-
-static int set_property(const char *name, const char *value, void *opaque)
-{
- DeviceState *dev = opaque;
-
- if (strcmp(name, "driver") == 0)
- return 0;
- if (strcmp(name, "bus") == 0)
- return 0;
-
- if (qdev_prop_parse(dev, name, value) == -1) {
- return -1;
- }
- return 0;
-}
-
-int qdev_device_help(QemuOpts *opts)
-{
- const char *driver;
- DeviceInfo *info;
- Property *prop;
-
- driver = qemu_opt_get(opts, "driver");
- if (driver && !strcmp(driver, "?")) {
- for (info = device_info_list; info != NULL; info = info->next) {
- if (info->no_user) {
- continue; /* not available, don't show */
- }
- qdev_print_devinfo(info);
- }
- return 1;
- }
-
- if (!driver || !qemu_opt_get(opts, "?")) {
- return 0;
- }
-
- info = qdev_find_info(NULL, driver);
- if (!info) {
- return 0;
- }
-
- for (prop = info->props; prop && prop->name; prop++) {
- /*
- * TODO Properties without a parser are just for dirty hacks.
- * qdev_prop_ptr is the only such PropertyInfo. It's marked
- * for removal. This conditional should be removed along with
- * it.
- */
- if (!prop->info->parse) {
- continue; /* no way to set it, don't show */
- }
- error_printf("%s.%s=%s\n", info->name, prop->name,
- prop->info->legacy_name ?: prop->info->name);
- }
- for (prop = info->bus_info->props; prop && prop->name; prop++) {
- if (!prop->info->parse) {
- continue; /* no way to set it, don't show */
- }
- error_printf("%s.%s=%s\n", info->name, prop->name,
- prop->info->legacy_name ?: prop->info->name);
- }
- return 1;
-}
-
-static DeviceState *qdev_get_peripheral(void)
-{
- static DeviceState *dev;
-
- if (dev == NULL) {
- dev = qdev_create(NULL, "container");
- qdev_property_add_child(qdev_get_root(), "peripheral", dev, NULL);
- qdev_init_nofail(dev);
+ if (!bus) {
+ bus = sysbus_get_default();
}
- return dev;
-}
-
-static DeviceState *qdev_get_peripheral_anon(void)
-{
- static DeviceState *dev;
-
- if (dev == NULL) {
- dev = qdev_create(NULL, "container");
- qdev_property_add_child(qdev_get_root(), "peripheral-anon", dev, NULL);
- qdev_init_nofail(dev);
- }
+ qdev_set_parent_bus(dev, bus);
+ qdev_prop_set_globals(dev);
return dev;
}
-DeviceState *qdev_device_add(QemuOpts *opts)
-{
- const char *driver, *path, *id;
- DeviceInfo *info;
- DeviceState *qdev;
- BusState *bus;
-
- driver = qemu_opt_get(opts, "driver");
- if (!driver) {
- qerror_report(QERR_MISSING_PARAMETER, "driver");
- return NULL;
- }
-
- /* find driver */
- info = qdev_find_info(NULL, driver);
- if (!info || info->no_user) {
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "driver", "a driver name");
- error_printf_unless_qmp("Try with argument '?' for a list.\n");
- return NULL;
- }
-
- /* find bus */
- path = qemu_opt_get(opts, "bus");
- if (path != NULL) {
- bus = qbus_find(path);
- if (!bus) {
- return NULL;
- }
- if (bus->info != info->bus_info) {
- qerror_report(QERR_BAD_BUS_FOR_DEVICE,
- driver, bus->info->name);
- return NULL;
- }
- } else {
- bus = qbus_find_recursive(main_system_bus, NULL, info->bus_info);
- if (!bus) {
- qerror_report(QERR_NO_BUS_FOR_DEVICE,
- info->name, info->bus_info->name);
- return NULL;
- }
- }
- if (qdev_hotplug && !bus->allow_hotplug) {
- qerror_report(QERR_BUS_NO_HOTPLUG, bus->name);
- return NULL;
- }
-
- /* create device, set properties */
- qdev = qdev_create_from_info(bus, info);
- id = qemu_opts_id(opts);
- if (id) {
- qdev->id = id;
- qdev_property_add_child(qdev_get_peripheral(), qdev->id, qdev, NULL);
- } else {
- static int anon_count;
- gchar *name = g_strdup_printf("device[%d]", anon_count++);
- qdev_property_add_child(qdev_get_peripheral_anon(), name,
- qdev, NULL);
- g_free(name);
- }
- if (qemu_opt_foreach(opts, set_property, qdev, 1) != 0) {
- qdev_free(qdev);
- return NULL;
- }
- if (qdev_init(qdev) < 0) {
- qerror_report(QERR_DEVICE_INIT_FAILED, driver);
- return NULL;
- }
- qdev->opts = opts;
- return qdev;
-}
-
/* Initialize a device. Device properties should be set before calling
this function. IRQs and MMIO regions should be connected/mapped after
calling this function.
@@ -340,22 +139,24 @@ DeviceState *qdev_device_add(QemuOpts *opts)
Return 0 on success. */
int qdev_init(DeviceState *dev)
{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
int rc;
assert(dev->state == DEV_STATE_CREATED);
- rc = dev->info->init(dev, dev->info);
+
+ rc = dc->init(dev);
if (rc < 0) {
qdev_free(dev);
return rc;
}
- if (dev->info->vmsd) {
- vmstate_register_with_alias_id(dev, -1, dev->info->vmsd, dev,
+ if (qdev_get_vmsd(dev)) {
+ vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
dev->instance_id_alias,
dev->alias_required_for_version);
}
dev->state = DEV_STATE_INITIALIZED;
- if (dev->hotplugged && dev->info->reset) {
- dev->info->reset(dev);
+ if (dev->hotplugged) {
+ device_reset(dev);
}
return 0;
}
@@ -370,22 +171,22 @@ void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
int qdev_unplug(DeviceState *dev)
{
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
if (!dev->parent_bus->allow_hotplug) {
qerror_report(QERR_BUS_NO_HOTPLUG, dev->parent_bus->name);
return -1;
}
- assert(dev->info->unplug != NULL);
+ assert(dc->unplug != NULL);
qdev_hot_removed = true;
- return dev->info->unplug(dev);
+ return dc->unplug(dev);
}
static int qdev_reset_one(DeviceState *dev, void *opaque)
{
- if (dev->info->reset) {
- dev->info->reset(dev);
- }
+ device_reset(dev);
return 0;
}
@@ -421,6 +222,7 @@ void qbus_reset_all_fn(void *opaque)
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
+ object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
@@ -435,87 +237,17 @@ int qdev_simple_unplug_cb(DeviceState *dev)
way is somewhat unclean, and best avoided. */
void qdev_init_nofail(DeviceState *dev)
{
- DeviceInfo *info = dev->info;
-
if (qdev_init(dev) < 0) {
- error_report("Initialization of device %s failed", info->name);
+ error_report("Initialization of device %s failed",
+ object_get_typename(OBJECT(dev)));
exit(1);
}
}
-static void qdev_property_del_all(DeviceState *dev)
-{
- while (!QTAILQ_EMPTY(&dev->properties)) {
- DeviceProperty *prop = QTAILQ_FIRST(&dev->properties);
-
- QTAILQ_REMOVE(&dev->properties, prop, node);
-
- if (prop->release) {
- prop->release(dev, prop->name, prop->opaque);
- }
-
- g_free(prop->name);
- g_free(prop->type);
- g_free(prop);
- }
-}
-
-static void qdev_property_del_child(DeviceState *dev, DeviceState *child, Error **errp)
-{
- DeviceProperty *prop;
-
- QTAILQ_FOREACH(prop, &dev->properties, node) {
- if (strstart(prop->type, "child<", NULL) && prop->opaque == child) {
- break;
- }
- }
-
- g_assert(prop != NULL);
-
- QTAILQ_REMOVE(&dev->properties, prop, node);
-
- if (prop->release) {
- prop->release(dev, prop->name, prop->opaque);
- }
-
- g_free(prop->name);
- g_free(prop->type);
- g_free(prop);
-}
-
/* Unlink device from bus and free the structure. */
void qdev_free(DeviceState *dev)
{
- BusState *bus;
- Property *prop;
-
- qdev_property_del_all(dev);
-
- if (dev->state == DEV_STATE_INITIALIZED) {
- while (dev->num_child_bus) {
- bus = QLIST_FIRST(&dev->child_bus);
- qbus_free(bus);
- }
- if (dev->info->vmsd)
- vmstate_unregister(dev, dev->info->vmsd, dev);
- if (dev->info->exit)
- dev->info->exit(dev);
- if (dev->opts)
- qemu_opts_del(dev->opts);
- }
- QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
- for (prop = dev->info->props; prop && prop->name; prop++) {
- if (prop->info->free) {
- prop->info->free(dev, prop);
- }
- }
- if (dev->parent) {
- qdev_property_del_child(dev->parent, dev, NULL);
- }
- if (dev->ref != 0) {
- qerror_report(QERR_DEVICE_IN_USE, dev->id?:"");
- }
- g_free(dev);
+ object_delete(OBJECT(dev));
}
void qdev_machine_creation_done(void)
@@ -532,15 +264,6 @@ bool qdev_machine_modified(void)
return qdev_hot_added || qdev_hot_removed;
}
-/* Get a character (serial) device interface. */
-CharDriverState *qdev_init_chardev(DeviceState *dev)
-{
- static int next_serial;
-
- /* FIXME: This function needs to go away: use chardev properties! */
- return serial_hds[next_serial++];
-}
-
BusState *qdev_get_parent_bus(DeviceState *dev)
{
return dev->parent_bus;
@@ -644,34 +367,6 @@ int qdev_walk_children(DeviceState *dev, qdev_walkerfn *devfn,
return 0;
}
-static BusState *qbus_find_recursive(BusState *bus, const char *name,
- const BusInfo *info)
-{
- DeviceState *dev;
- BusState *child, *ret;
- int match = 1;
-
- if (name && (strcmp(bus->name, name) != 0)) {
- match = 0;
- }
- if (info && (bus->info != info)) {
- match = 0;
- }
- if (match) {
- return bus;
- }
-
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- ret = qbus_find_recursive(child, name, info);
- if (ret) {
- return ret;
- }
- }
- }
- return NULL;
-}
-
DeviceState *qdev_find_recursive(BusState *bus, const char *id)
{
DeviceState *dev, *ret;
@@ -690,162 +385,6 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
return NULL;
}
-static void qbus_list_bus(DeviceState *dev)
-{
- BusState *child;
- const char *sep = " ";
-
- error_printf("child busses at \"%s\":",
- dev->id ? dev->id : dev->info->name);
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- error_printf("%s\"%s\"", sep, child->name);
- sep = ", ";
- }
- error_printf("\n");
-}
-
-static void qbus_list_dev(BusState *bus)
-{
- DeviceState *dev;
- const char *sep = " ";
-
- error_printf("devices at \"%s\":", bus->name);
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- error_printf("%s\"%s\"", sep, dev->info->name);
- if (dev->id)
- error_printf("/\"%s\"", dev->id);
- sep = ", ";
- }
- error_printf("\n");
-}
-
-static BusState *qbus_find_bus(DeviceState *dev, char *elem)
-{
- BusState *child;
-
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- if (strcmp(child->name, elem) == 0) {
- return child;
- }
- }
- return NULL;
-}
-
-static DeviceState *qbus_find_dev(BusState *bus, char *elem)
-{
- DeviceState *dev;
-
- /*
- * try to match in order:
- * (1) instance id, if present
- * (2) driver name
- * (3) driver alias, if present
- */
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (dev->id && strcmp(dev->id, elem) == 0) {
- return dev;
- }
- }
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (strcmp(dev->info->name, elem) == 0) {
- return dev;
- }
- }
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
- return dev;
- }
- }
- return NULL;
-}
-
-static BusState *qbus_find(const char *path)
-{
- DeviceState *dev;
- BusState *bus;
- char elem[128];
- int pos, len;
-
- /* find start element */
- if (path[0] == '/') {
- bus = main_system_bus;
- pos = 0;
- } else {
- if (sscanf(path, "%127[^/]%n", elem, &len) != 1) {
- assert(!path[0]);
- elem[0] = len = 0;
- }
- bus = qbus_find_recursive(main_system_bus, elem, NULL);
- if (!bus) {
- qerror_report(QERR_BUS_NOT_FOUND, elem);
- return NULL;
- }
- pos = len;
- }
-
- for (;;) {
- assert(path[pos] == '/' || !path[pos]);
- while (path[pos] == '/') {
- pos++;
- }
- if (path[pos] == '\0') {
- return bus;
- }
-
- /* find device */
- if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
- assert(0);
- elem[0] = len = 0;
- }
- pos += len;
- dev = qbus_find_dev(bus, elem);
- if (!dev) {
- qerror_report(QERR_DEVICE_NOT_FOUND, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_dev(bus);
- }
- return NULL;
- }
-
- assert(path[pos] == '/' || !path[pos]);
- while (path[pos] == '/') {
- pos++;
- }
- if (path[pos] == '\0') {
- /* last specified element is a device. If it has exactly
- * one child bus accept it nevertheless */
- switch (dev->num_child_bus) {
- case 0:
- qerror_report(QERR_DEVICE_NO_BUS, elem);
- return NULL;
- case 1:
- return QLIST_FIRST(&dev->child_bus);
- default:
- qerror_report(QERR_DEVICE_MULTIPLE_BUSSES, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_bus(dev);
- }
- return NULL;
- }
- }
-
- /* find bus */
- if (sscanf(path+pos, "%127[^/]%n", elem, &len) != 1) {
- assert(0);
- elem[0] = len = 0;
- }
- pos += len;
- bus = qbus_find_bus(dev, elem);
- if (!bus) {
- qerror_report(QERR_BUS_NOT_FOUND, elem);
- if (!monitor_cur_is_qmp()) {
- qbus_list_bus(dev);
- }
- return NULL;
- }
- }
-}
-
void qbus_create_inplace(BusState *bus, BusInfo *info,
DeviceState *parent, const char *name)
{
@@ -926,112 +465,6 @@ void qbus_free(BusState *bus)
}
}
-#define qdev_printf(fmt, ...) monitor_printf(mon, "%*s" fmt, indent, "", ## __VA_ARGS__)
-static void qbus_print(Monitor *mon, BusState *bus, int indent);
-
-static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
- const char *prefix, int indent)
-{
- char buf[64];
-
- if (!props)
- return;
- while (props->name) {
- /*
- * TODO Properties without a print method are just for dirty
- * hacks. qdev_prop_ptr is the only such PropertyInfo. It's
- * marked for removal. The test props->info->print should be
- * removed along with it.
- */
- if (props->info->print) {
- props->info->print(dev, props, buf, sizeof(buf));
- qdev_printf("%s-prop: %s = %s\n", prefix, props->name, buf);
- }
- props++;
- }
-}
-
-static void qdev_print(Monitor *mon, DeviceState *dev, int indent)
-{
- BusState *child;
- qdev_printf("dev: %s, id \"%s\"\n", dev->info->name,
- dev->id ? dev->id : "");
- indent += 2;
- if (dev->num_gpio_in) {
- qdev_printf("gpio-in %d\n", dev->num_gpio_in);
- }
- if (dev->num_gpio_out) {
- qdev_printf("gpio-out %d\n", dev->num_gpio_out);
- }
- qdev_print_props(mon, dev, dev->info->props, "dev", indent);
- qdev_print_props(mon, dev, dev->parent_bus->info->props, "bus", indent);
- if (dev->parent_bus->info->print_dev)
- dev->parent_bus->info->print_dev(mon, dev, indent);
- QLIST_FOREACH(child, &dev->child_bus, sibling) {
- qbus_print(mon, child, indent);
- }
-}
-
-static void qbus_print(Monitor *mon, BusState *bus, int indent)
-{
- struct DeviceState *dev;
-
- qdev_printf("bus: %s\n", bus->name);
- indent += 2;
- qdev_printf("type %s\n", bus->info->name);
- QTAILQ_FOREACH(dev, &bus->children, sibling) {
- qdev_print(mon, dev, indent);
- }
-}
-#undef qdev_printf
-
-void do_info_qtree(Monitor *mon)
-{
- if (main_system_bus)
- qbus_print(mon, main_system_bus, 0);
-}
-
-void do_info_qdm(Monitor *mon)
-{
- DeviceInfo *info;
-
- for (info = device_info_list; info != NULL; info = info->next) {
- qdev_print_devinfo(info);
- }
-}
-
-int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- QemuOpts *opts;
-
- opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict);
- if (!opts) {
- return -1;
- }
- if (!monitor_cur_is_qmp() && qdev_device_help(opts)) {
- qemu_opts_del(opts);
- return 0;
- }
- if (!qdev_device_add(opts)) {
- qemu_opts_del(opts);
- return -1;
- }
- return 0;
-}
-
-int do_device_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *id = qdict_get_str(qdict, "id");
- DeviceState *dev;
-
- dev = qdev_find_recursive(main_system_bus, id);
- if (NULL == dev) {
- qerror_report(QERR_DEVICE_NOT_FOUND, id);
- return -1;
- }
- return qdev_unplug(dev);
-}
-
static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
{
int l = 0;
@@ -1044,7 +477,7 @@ static int qdev_get_fw_dev_path_helper(DeviceState *dev, char *p, int size)
l += snprintf(p + l, size - l, "%s", d);
g_free(d);
} else {
- l += snprintf(p + l, size - l, "%s", dev->info->name);
+ l += snprintf(p + l, size - l, "%s", object_get_typename(OBJECT(dev)));
}
}
l += snprintf(p + l , size - l, "/");
@@ -1064,106 +497,19 @@ char* qdev_get_fw_dev_path(DeviceState *dev)
return strdup(path);
}
-char *qdev_get_type(DeviceState *dev, Error **errp)
+static char *qdev_get_type(Object *obj, Error **errp)
{
- return g_strdup(dev->info->name);
-}
-
-void qdev_ref(DeviceState *dev)
-{
- dev->ref++;
-}
-
-void qdev_unref(DeviceState *dev)
-{
- g_assert(dev->ref > 0);
- dev->ref--;
-}
-
-void qdev_property_add(DeviceState *dev, const char *name, const char *type,
- DevicePropertyAccessor *get, DevicePropertyAccessor *set,
- DevicePropertyRelease *release,
- void *opaque, Error **errp)
-{
- DeviceProperty *prop = g_malloc0(sizeof(*prop));
-
- prop->name = g_strdup(name);
- prop->type = g_strdup(type);
-
- prop->get = get;
- prop->set = set;
- prop->release = release;
- prop->opaque = opaque;
-
- QTAILQ_INSERT_TAIL(&dev->properties, prop, node);
-}
-
-static DeviceProperty *qdev_property_find(DeviceState *dev, const char *name)
-{
- DeviceProperty *prop;
-
- QTAILQ_FOREACH(prop, &dev->properties, node) {
- if (strcmp(prop->name, name) == 0) {
- return prop;
- }
- }
-
- return NULL;
-}
-
-void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
- Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return;
- }
-
- if (!prop->get) {
- error_set(errp, QERR_PERMISSION_DENIED);
- } else {
- prop->get(dev, v, prop->opaque, name, errp);
- }
-}
-
-void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
- Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return;
- }
-
- if (!prop->set) {
- error_set(errp, QERR_PERMISSION_DENIED);
- } else {
- prop->set(dev, v, prop->opaque, name, errp);
- }
-}
-
-const char *qdev_property_get_type(DeviceState *dev, const char *name, Error **errp)
-{
- DeviceProperty *prop = qdev_property_find(dev, name);
-
- if (prop == NULL) {
- error_set(errp, QERR_PROPERTY_NOT_FOUND, dev->id?:"", name);
- return NULL;
- }
-
- return prop->type;
+ return g_strdup(object_get_typename(obj));
}
/**
* Legacy property handling
*/
-static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_get_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
char buffer[1024];
@@ -1173,9 +519,10 @@ static void qdev_get_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
visit_type_str(v, &ptr, name, errp);
}
-static void qdev_set_legacy_property(DeviceState *dev, Visitor *v, void *opaque,
+static void qdev_set_legacy_property(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
+ DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
Error *local_err = NULL;
char *ptr = NULL;
@@ -1215,11 +562,11 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
type = g_strdup_printf("legacy<%s>",
prop->info->legacy_name ?: prop->info->name);
- qdev_property_add(dev, name, type,
- prop->info->print ? qdev_get_legacy_property : NULL,
- prop->info->parse ? qdev_set_legacy_property : NULL,
- NULL,
- prop, errp);
+ object_property_add(OBJECT(dev), name, type,
+ prop->info->print ? qdev_get_legacy_property : NULL,
+ prop->info->parse ? qdev_set_legacy_property : NULL,
+ NULL,
+ prop, errp);
g_free(type);
g_free(name);
@@ -1234,337 +581,87 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
void qdev_property_add_static(DeviceState *dev, Property *prop,
Error **errp)
{
- qdev_property_add(dev, prop->name, prop->info->name,
- prop->info->get, prop->info->set,
- NULL,
- prop, errp);
-}
-
-DeviceState *qdev_get_root(void)
-{
- static DeviceState *qdev_root;
-
- if (!qdev_root) {
- qdev_root = qdev_create(NULL, "container");
- qdev_init_nofail(qdev_root);
- }
-
- return qdev_root;
-}
-
-static void qdev_get_child_property(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- DeviceState *child = opaque;
- gchar *path;
-
- path = qdev_get_canonical_path(child);
- visit_type_str(v, &path, name, errp);
- g_free(path);
+ object_property_add(OBJECT(dev), prop->name, prop->info->name,
+ prop->info->get, prop->info->set,
+ NULL,
+ prop, errp);
}
-static void qdev_release_child_property(DeviceState *dev, const char *name,
- void *opaque)
+static void device_initfn(Object *obj)
{
- DeviceState *child = opaque;
-
- qdev_unref(child);
-}
-
-void qdev_property_add_child(DeviceState *dev, const char *name,
- DeviceState *child, Error **errp)
-{
- gchar *type;
-
- type = g_strdup_printf("child<%s>", child->info->name);
-
- qdev_property_add(dev, name, type, qdev_get_child_property,
- NULL, qdev_release_child_property,
- child, errp);
-
- qdev_ref(child);
- g_assert(child->parent == NULL);
- child->parent = dev;
-
- g_free(type);
-}
-
-static void qdev_get_link_property(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- DeviceState **child = opaque;
- gchar *path;
-
- if (*child) {
- path = qdev_get_canonical_path(*child);
- visit_type_str(v, &path, name, errp);
- g_free(path);
- } else {
- path = (gchar *)"";
- visit_type_str(v, &path, name, errp);
- }
-}
-
-static void qdev_set_link_property(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- DeviceState **child = opaque;
- bool ambiguous = false;
- const char *type;
- char *path;
-
- type = qdev_property_get_type(dev, name, NULL);
-
- visit_type_str(v, &path, name, errp);
-
- if (*child) {
- qdev_unref(*child);
- }
-
- if (strcmp(path, "") != 0) {
- DeviceState *target;
-
- target = qdev_resolve_path(path, &ambiguous);
- if (target) {
- gchar *target_type;
-
- target_type = g_strdup_printf("link<%s>", target->info->name);
- if (strcmp(target_type, type) == 0) {
- *child = target;
- qdev_ref(target);
- } else {
- error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
- }
+ DeviceState *dev = DEVICE(obj);
+ Property *prop;
- g_free(target_type);
- } else {
- error_set(errp, QERR_DEVICE_NOT_FOUND, path);
- }
- } else {
- *child = NULL;
+ if (qdev_hotplug) {
+ dev->hotplugged = 1;
+ qdev_hot_added = true;
}
- g_free(path);
-}
-
-void qdev_property_add_link(DeviceState *dev, const char *name,
- const char *type, DeviceState **child,
- Error **errp)
-{
- gchar *full_type;
-
- full_type = g_strdup_printf("link<%s>", type);
-
- qdev_property_add(dev, name, full_type,
- qdev_get_link_property,
- qdev_set_link_property,
- NULL, child, errp);
-
- g_free(full_type);
-}
-
-gchar *qdev_get_canonical_path(DeviceState *dev)
-{
- DeviceState *root = qdev_get_root();
- char *newpath = NULL, *path = NULL;
-
- while (dev != root) {
- DeviceProperty *prop = NULL;
-
- g_assert(dev->parent != NULL);
-
- QTAILQ_FOREACH(prop, &dev->parent->properties, node) {
- if (!strstart(prop->type, "child<", NULL)) {
- continue;
- }
-
- if (prop->opaque == dev) {
- if (path) {
- newpath = g_strdup_printf("%s/%s", prop->name, path);
- g_free(path);
- path = newpath;
- } else {
- path = g_strdup(prop->name);
- }
- break;
- }
- }
-
- g_assert(prop != NULL);
+ dev->instance_id_alias = -1;
+ dev->state = DEV_STATE_CREATED;
- dev = dev->parent;
+ qdev_prop_set_defaults(dev, qdev_get_props(dev));
+ for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+ qdev_property_add_legacy(dev, prop, NULL);
+ qdev_property_add_static(dev, prop, NULL);
}
- newpath = g_strdup_printf("/%s", path);
- g_free(path);
-
- return newpath;
+ object_property_add_str(OBJECT(dev), "type", qdev_get_type, NULL, NULL);
}
-static DeviceState *qdev_resolve_abs_path(DeviceState *parent,
- gchar **parts,
- int index)
+/* Unlink device from bus and free the structure. */
+static void device_finalize(Object *obj)
{
- DeviceProperty *prop;
- DeviceState *child;
-
- if (parts[index] == NULL) {
- return parent;
- }
-
- if (strcmp(parts[index], "") == 0) {
- return qdev_resolve_abs_path(parent, parts, index + 1);
- }
-
- prop = qdev_property_find(parent, parts[index]);
- if (prop == NULL) {
- return NULL;
- }
+ DeviceState *dev = DEVICE(obj);
+ BusState *bus;
+ Property *prop;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
- child = NULL;
- if (strstart(prop->type, "link<", NULL)) {
- DeviceState **pchild = prop->opaque;
- if (*pchild) {
- child = *pchild;
+ if (dev->state == DEV_STATE_INITIALIZED) {
+ while (dev->num_child_bus) {
+ bus = QLIST_FIRST(&dev->child_bus);
+ qbus_free(bus);
}
- } else if (strstart(prop->type, "child<", NULL)) {
- child = prop->opaque;
- }
-
- if (!child) {
- return NULL;
- }
-
- return qdev_resolve_abs_path(child, parts, index + 1);
-}
-
-static DeviceState *qdev_resolve_partial_path(DeviceState *parent,
- gchar **parts,
- bool *ambiguous)
-{
- DeviceState *dev;
- DeviceProperty *prop;
-
- dev = qdev_resolve_abs_path(parent, parts, 0);
-
- QTAILQ_FOREACH(prop, &parent->properties, node) {
- DeviceState *found;
-
- if (!strstart(prop->type, "child<", NULL)) {
- continue;
+ if (qdev_get_vmsd(dev)) {
+ vmstate_unregister(dev, qdev_get_vmsd(dev), dev);
}
-
- found = qdev_resolve_partial_path(prop->opaque, parts, ambiguous);
- if (found) {
- if (dev) {
- if (ambiguous) {
- *ambiguous = true;
- }
- return NULL;
- }
- dev = found;
+ if (dc->exit) {
+ dc->exit(dev);
}
-
- if (ambiguous && *ambiguous) {
- return NULL;
+ if (dev->opts) {
+ qemu_opts_del(dev->opts);
}
}
-
- return dev;
-}
-
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous)
-{
- bool partial_path = true;
- DeviceState *dev;
- gchar **parts;
-
- parts = g_strsplit(path, "/", 0);
- if (parts == NULL || parts[0] == NULL) {
- g_strfreev(parts);
- return qdev_get_root();
- }
-
- if (strcmp(parts[0], "") == 0) {
- partial_path = false;
- }
-
- if (partial_path) {
- if (ambiguous) {
- *ambiguous = false;
+ QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
+ for (prop = qdev_get_props(dev); prop && prop->name; prop++) {
+ if (prop->info->free) {
+ prop->info->free(dev, prop);
}
- dev = qdev_resolve_partial_path(qdev_get_root(), parts, ambiguous);
- } else {
- dev = qdev_resolve_abs_path(qdev_get_root(), parts, 1);
- }
-
- g_strfreev(parts);
-
- return dev;
-}
-
-typedef struct StringProperty
-{
- char *(*get)(DeviceState *, Error **);
- void (*set)(DeviceState *, const char *, Error **);
-} StringProperty;
-
-static void qdev_property_get_str(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
-{
- StringProperty *prop = opaque;
- char *value;
-
- value = prop->get(dev, errp);
- if (value) {
- visit_type_str(v, &value, name, errp);
- g_free(value);
}
}
-static void qdev_property_set_str(DeviceState *dev, Visitor *v, void *opaque,
- const char *name, Error **errp)
+void device_reset(DeviceState *dev)
{
- StringProperty *prop = opaque;
- char *value;
- Error *local_err = NULL;
+ DeviceClass *klass = DEVICE_GET_CLASS(dev);
- visit_type_str(v, &value, name, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
+ if (klass->reset) {
+ klass->reset(dev);
}
-
- prop->set(dev, value, errp);
- g_free(value);
}
-static void qdev_property_release_str(DeviceState *dev, const char *name,
- void *opaque)
-{
- StringProperty *prop = opaque;
- g_free(prop);
-}
+static TypeInfo device_type_info = {
+ .name = TYPE_DEVICE,
+ .parent = TYPE_OBJECT,
+ .instance_size = sizeof(DeviceState),
+ .instance_init = device_initfn,
+ .instance_finalize = device_finalize,
+ .abstract = true,
+ .class_size = sizeof(DeviceClass),
+};
-void qdev_property_add_str(DeviceState *dev, const char *name,
- char *(*get)(DeviceState *, Error **),
- void (*set)(DeviceState *, const char *, Error **),
- Error **errp)
+static void init_qdev(void)
{
- StringProperty *prop = g_malloc0(sizeof(*prop));
-
- prop->get = get;
- prop->set = set;
-
- qdev_property_add(dev, name, "string",
- get ? qdev_property_get_str : NULL,
- set ? qdev_property_set_str : NULL,
- qdev_property_release_str,
- prop, errp);
+ type_register_static(&device_type_info);
}
-void qdev_machine_init(void)
-{
- qdev_get_peripheral_anon();
- qdev_get_peripheral();
-}
+device_init(init_qdev);
diff --git a/hw/qdev.h b/hw/qdev.h
index 2abb767389..ab53273632 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -6,6 +6,7 @@
#include "qemu-char.h"
#include "qemu-option.h"
#include "qapi/qapi-visit-core.h"
+#include "qemu/object.h"
typedef struct Property Property;
@@ -13,8 +14,6 @@ typedef struct PropertyInfo PropertyInfo;
typedef struct CompatProperty CompatProperty;
-typedef struct DeviceInfo DeviceInfo;
-
typedef struct BusState BusState;
typedef struct BusInfo BusInfo;
@@ -28,52 +27,45 @@ enum {
DEV_NVECTORS_UNSPECIFIED = -1,
};
-/**
- * @DevicePropertyAccessor - called when trying to get/set a property
- *
- * @dev the device that owns the property
- * @v the visitor that contains the property data
- * @opaque the device property opaque
- * @name the name of the property
- * @errp a pointer to an Error that is filled if getting/setting fails.
- */
-typedef void (DevicePropertyAccessor)(DeviceState *dev,
- Visitor *v,
- void *opaque,
- const char *name,
- Error **errp);
+#define TYPE_DEVICE "device"
+#define DEVICE(obj) OBJECT_CHECK(DeviceState, (obj), TYPE_DEVICE)
+#define DEVICE_CLASS(klass) OBJECT_CLASS_CHECK(DeviceClass, (klass), TYPE_DEVICE)
+#define DEVICE_GET_CLASS(obj) OBJECT_GET_CLASS(DeviceClass, (obj), TYPE_DEVICE)
-/**
- * @DevicePropertyRelease - called when a property is removed from a device
- *
- * @dev the device that owns the property
- * @name the name of the property
- * @opaque the opaque registered with the property
- */
-typedef void (DevicePropertyRelease)(DeviceState *dev,
- const char *name,
- void *opaque);
-
-typedef struct DeviceProperty
-{
- gchar *name;
- gchar *type;
- DevicePropertyAccessor *get;
- DevicePropertyAccessor *set;
- DevicePropertyRelease *release;
- void *opaque;
-
- QTAILQ_ENTRY(DeviceProperty) node;
-} DeviceProperty;
+typedef int (*qdev_initfn)(DeviceState *dev);
+typedef int (*qdev_event)(DeviceState *dev);
+typedef void (*qdev_resetfn)(DeviceState *dev);
+
+typedef struct DeviceClass {
+ ObjectClass parent_class;
+
+ const char *fw_name;
+ const char *desc;
+ Property *props;
+ int no_user;
+
+ /* callbacks */
+ void (*reset)(DeviceState *dev);
+
+ /* device state */
+ const VMStateDescription *vmsd;
+
+ /* Private to qdev / bus. */
+ qdev_initfn init;
+ qdev_event unplug;
+ qdev_event exit;
+ BusInfo *bus_info;
+} DeviceClass;
/* This structure should not be accessed directly. We declare it here
so that it can be embedded in individual device state structures. */
struct DeviceState {
+ Object parent_obj;
+
const char *id;
enum DevState state;
QemuOpts *opts;
int hotplugged;
- DeviceInfo *info;
BusState *parent_bus;
int num_gpio_out;
qemu_irq *gpio_out;
@@ -84,18 +76,6 @@ struct DeviceState {
QTAILQ_ENTRY(DeviceState) sibling;
int instance_id_alias;
int alias_required_for_version;
-
- /**
- * This tracks the number of references between devices. See @qdev_ref for
- * more information.
- */
- uint32_t ref;
-
- QTAILQ_HEAD(, DeviceProperty) properties;
-
- /* Do not, under any circumstance, use this parent link below anywhere
- * outside of qdev.c. You have been warned. */
- DeviceState *parent;
};
typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
@@ -145,6 +125,7 @@ enum PropertyType {
PROP_TYPE_UINT64,
PROP_TYPE_TADDR,
PROP_TYPE_MACADDR,
+ PROP_TYPE_LOSTTICKPOLICY,
PROP_TYPE_DRIVE,
PROP_TYPE_CHR,
PROP_TYPE_STRING,
@@ -164,8 +145,8 @@ struct PropertyInfo {
int (*parse)(DeviceState *dev, Property *prop, const char *str);
int (*print)(DeviceState *dev, Property *prop, char *dest, size_t len);
void (*free)(DeviceState *dev, Property *prop);
- DevicePropertyAccessor *get;
- DevicePropertyAccessor *set;
+ ObjectPropertyAccessor *get;
+ ObjectPropertyAccessor *set;
};
typedef struct GlobalProperty {
@@ -179,6 +160,7 @@ typedef struct GlobalProperty {
DeviceState *qdev_create(BusState *bus, const char *name);
DeviceState *qdev_try_create(BusState *bus, const char *name);
+bool qdev_exists(const char *name);
int qdev_device_help(QemuOpts *opts);
DeviceState *qdev_device_add(QemuOpts *opts);
int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
@@ -198,43 +180,11 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
/*** Device API. ***/
-typedef int (*qdev_initfn)(DeviceState *dev, DeviceInfo *info);
-typedef int (*qdev_event)(DeviceState *dev);
-typedef void (*qdev_resetfn)(DeviceState *dev);
-
-struct DeviceInfo {
- const char *name;
- const char *fw_name;
- const char *alias;
- const char *desc;
- size_t size;
- Property *props;
- int no_user;
-
- /* callbacks */
- qdev_resetfn reset;
-
- /* device state */
- const VMStateDescription *vmsd;
-
- /* Private to qdev / bus. */
- qdev_initfn init;
- qdev_event unplug;
- qdev_event exit;
- BusInfo *bus_info;
- struct DeviceInfo *next;
-};
-extern DeviceInfo *device_info_list;
-
-void qdev_register(DeviceInfo *info);
-
/* Register device properties. */
/* GPIO inputs also double as IRQ sinks. */
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
-CharDriverState *qdev_init_chardev(DeviceState *dev);
-
BusState *qdev_get_parent_bus(DeviceState *dev);
/*** BUS API. ***/
@@ -287,6 +237,7 @@ extern PropertyInfo qdev_prop_string;
extern PropertyInfo qdev_prop_chr;
extern PropertyInfo qdev_prop_ptr;
extern PropertyInfo qdev_prop_macaddr;
+extern PropertyInfo qdev_prop_losttickpolicy;
extern PropertyInfo qdev_prop_drive;
extern PropertyInfo qdev_prop_netdev;
extern PropertyInfo qdev_prop_vlan;
@@ -347,6 +298,9 @@ extern PropertyInfo qdev_prop_pci_devfn;
DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
#define DEFINE_PROP_MACADDR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_macaddr, MACAddr)
+#define DEFINE_PROP_LOSTTICKPOLICY(_n, _s, _f, _d) \
+ DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_losttickpolicy, \
+ LostTickPolicy)
#define DEFINE_PROP_END_OF_LIST() \
{}
@@ -369,6 +323,8 @@ void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value);
int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) QEMU_WARN_UNUSED_RESULT;
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverState *value);
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
+void qdev_prop_set_losttickpolicy(DeviceState *dev, const char *name,
+ LostTickPolicy *value);
/* FIXME: Remove opaque pointer properties. */
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value);
void qdev_prop_set_defaults(DeviceState *dev, Property *props);
@@ -378,250 +334,43 @@ void qdev_prop_set_globals(DeviceState *dev);
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
Property *prop, const char *value);
-static inline const char *qdev_fw_name(DeviceState *dev)
-{
- return dev->info->fw_name ? : dev->info->alias ? : dev->info->name;
-}
-
char *qdev_get_fw_dev_path(DeviceState *dev);
+
/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
extern struct BusInfo system_bus_info;
/**
- * @qdev_ref
- *
- * Increase the reference count of a device. A device cannot be freed as long
- * as its reference count is greater than zero.
- *
- * @dev - the device
- */
-void qdev_ref(DeviceState *dev);
-
-/**
- * @qdef_unref
- *
- * Decrease the reference count of a device. A device cannot be freed as long
- * as its reference count is greater than zero.
- *
- * @dev - the device
- */
-void qdev_unref(DeviceState *dev);
-
-/**
- * @qdev_property_add - add a new property to a device
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property. This can contain any character except for
- * a forward slash. In general, you should use hyphens '-' instead of
- * underscores '_' when naming properties.
- *
- * @type - the type name of the property. This namespace is pretty loosely
- * defined. Sub namespaces are constructed by using a prefix and then
- * to angle brackets. For instance, the type 'virtio-net-pci' in the
- * 'link' namespace would be 'link<virtio-net-pci>'.
- *
- * @get - the getter to be called to read a property. If this is NULL, then
- * the property cannot be read.
- *
- * @set - the setter to be called to write a property. If this is NULL,
- * then the property cannot be written.
- *
- * @release - called when the property is removed from the device. This is
- * meant to allow a property to free its opaque upon device
- * destruction. This may be NULL.
- *
- * @opaque - an opaque pointer to pass to the callbacks for the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_add(DeviceState *dev, const char *name, const char *type,
- DevicePropertyAccessor *get, DevicePropertyAccessor *set,
- DevicePropertyRelease *release,
- void *opaque, Error **errp);
-
-/**
- * @qdev_property_get - reads a property from a device
- *
- * @dev - the device
- *
- * @v - the visitor that will receive the property value. This should be an
- * Output visitor and the data will be written with @name as the name.
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_get(DeviceState *dev, Visitor *v, const char *name,
- Error **errp);
-
-/**
- * @qdev_property_set - writes a property to a device
- *
- * @dev - the device
- *
- * @v - the visitor that will be used to write the property value. This should
- * be an Input visitor and the data will be first read with @name as the
- * name and then written as the property value.
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- */
-void qdev_property_set(DeviceState *dev, Visitor *v, const char *name,
- Error **errp);
-
-/**
- * @qdev_property_get_type - returns the type of a property
- *
- * @dev - the device
- *
- * @name - the name of the property
- *
- * @errp - returns an error if this function fails
- *
- * Returns:
- * The type name of the property.
- */
-const char *qdev_property_get_type(DeviceState *dev, const char *name,
- Error **errp);
-
-/**
* @qdev_property_add_static - add a @Property to a device referencing a
* field in a struct.
*/
void qdev_property_add_static(DeviceState *dev, Property *prop, Error **errp);
/**
- * @qdev_get_root - returns the root device of the composition tree
+ * @qdev_machine_init
*
- * Returns:
- * The root of the composition tree.
+ * Initialize platform devices before machine init. This is a hack until full
+ * support for composition is added.
*/
-DeviceState *qdev_get_root(void);
+void qdev_machine_init(void);
/**
- * @qdev_get_canonical_path - returns the canonical path for a device. This
- * is the path within the composition tree starting from the root.
+ * @device_reset
*
- * Returns:
- * The canonical path in the composition tree.
+ * Reset a single device (by calling the reset method).
*/
-gchar *qdev_get_canonical_path(DeviceState *dev);
+void device_reset(DeviceState *dev);
-/**
- * @qdev_resolve_path - resolves a path returning a device
- *
- * There are two types of supported paths--absolute paths and partial paths.
- *
- * Absolute paths are derived from the root device and can follow child<> or
- * link<> properties. Since they can follow link<> properties, they can be
- * arbitrarily long. Absolute paths look like absolute filenames and are
- * prefixed with a leading slash.
- *
- * Partial paths look like relative filenames. They do not begin with a
- * prefix. The matching rules for partial paths are subtle but designed to make
- * specifying devices easy. At each level of the composition tree, the partial
- * path is matched as an absolute path. The first match is not returned. At
- * least two matches are searched for. A successful result is only returned if
- * only one match is founded. If more than one match is found, a flag is
- * return to indicate that the match was ambiguous.
- *
- * @path - the path to resolve
- *
- * @ambiguous - returns true if the path resolution failed because of an
- * ambiguous match
- *
- * Returns:
- * The matched device or NULL on path lookup failure.
- */
-DeviceState *qdev_resolve_path(const char *path, bool *ambiguous);
+const VMStateDescription *qdev_get_vmsd(DeviceState *dev);
-/**
- * @qdev_property_add_child - Add a child property to a device
- *
- * Child properties form the composition tree. All devices need to be a child
- * of another device. Devices can only be a child of one device.
- *
- * There is no way for a child to determine what its parent is. It is not
- * a bidirectional relationship. This is by design.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @child - the child device
- *
- * @errp - if an error occurs, a pointer to an area to store the area
- */
-void qdev_property_add_child(DeviceState *dev, const char *name,
- DeviceState *child, Error **errp);
+const char *qdev_fw_name(DeviceState *dev);
-/**
- * @qdev_property_add_link - Add a link property to a device
- *
- * Links establish relationships between devices. Links are unidirectional
- * although two links can be combined to form a bidirectional relationship
- * between devices.
- *
- * Links form the graph in the device model.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @type - the qdev type of the link
- *
- * @child - a pointer to where the link device reference is stored
- *
- * @errp - if an error occurs, a pointer to an area to store the area
- */
-void qdev_property_add_link(DeviceState *dev, const char *name,
- const char *type, DeviceState **child,
- Error **errp);
+BusInfo *qdev_get_bus_info(DeviceState *dev);
-/**
- * @qdev_property_add_str
- *
- * Add a string property using getters/setters. This function will add a
- * property of type 'string'.
- *
- * @dev - the device to add a property to
- *
- * @name - the name of the property
- *
- * @get - the getter or NULL if the property is write-only. This function must
- * return a string to be freed by @g_free().
- *
- * @set - the setter or NULL if the property is read-only
- *
- * @errp - if an error occurs, a pointer to an area to store the error
- */
-void qdev_property_add_str(DeviceState *dev, const char *name,
- char *(*get)(DeviceState *, Error **),
- void (*set)(DeviceState *, const char *, Error **),
- Error **errp);
+Property *qdev_get_props(DeviceState *dev);
-/**
- * @qdev_get_type
- *
- * Returns the string representation of the type of this object.
- *
- * @dev - the device
- *
- * @errp - if an error occurs, a pointer to an area to store the error
- *
- * Returns: a string representing the type. This must be freed by the caller
- * with g_free().
- */
-char *qdev_get_type(DeviceState *dev, Error **errp);
+/* FIXME: make this a link<> */
+void qdev_set_parent_bus(DeviceState *dev, BusState *bus);
-/**
- * @qdev_machine_init
- *
- * Initialize platform devices before machine init. This is a hack until full
- * support for composition is added.
- */
-void qdev_machine_init(void);
+extern int qdev_hotplug;
#endif
diff --git a/hw/qxl.c b/hw/qxl.c
index ac819271b2..bc03c1dc77 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -343,10 +343,7 @@ static void init_qxl_ram(PCIQXLDevice *d)
/* can be called from spice server thread context */
static void qxl_set_dirty(MemoryRegion *mr, ram_addr_t addr, ram_addr_t end)
{
- while (addr < end) {
- memory_region_set_dirty(mr, addr);
- addr += TARGET_PAGE_SIZE;
- }
+ memory_region_set_dirty(mr, addr, end - addr);
}
static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
@@ -1020,7 +1017,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
case MEMSLOT_GROUP_HOST:
return (void*)offset;
case MEMSLOT_GROUP_GUEST:
- PANIC_ON(slot > NUM_MEMSLOTS);
+ PANIC_ON(slot >= NUM_MEMSLOTS);
PANIC_ON(!qxl->guest_slots[slot].active);
PANIC_ON(offset < qxl->guest_slots[slot].delta);
offset -= qxl->guest_slots[slot].delta;
@@ -1827,38 +1824,56 @@ static Property qxl_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
-static PCIDeviceInfo qxl_info_primary = {
- .qdev.name = "qxl-vga",
- .qdev.desc = "Spice QXL GPU (primary, vga compatible)",
- .qdev.size = sizeof(PCIQXLDevice),
- .qdev.reset = qxl_reset_handler,
- .qdev.vmsd = &qxl_vmstate,
- .no_hotplug = 1,
- .init = qxl_init_primary,
- .romfile = "vgabios-qxl.bin",
- .vendor_id = REDHAT_PCI_VENDOR_ID,
- .device_id = QXL_DEVICE_ID_STABLE,
- .class_id = PCI_CLASS_DISPLAY_VGA,
- .qdev.props = qxl_properties,
+static void qxl_primary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = qxl_init_primary;
+ k->romfile = "vgabios-qxl.bin";
+ k->vendor_id = REDHAT_PCI_VENDOR_ID;
+ k->device_id = QXL_DEVICE_ID_STABLE;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->desc = "Spice QXL GPU (primary, vga compatible)";
+ dc->reset = qxl_reset_handler;
+ dc->vmsd = &qxl_vmstate;
+ dc->props = qxl_properties;
+}
+
+static TypeInfo qxl_primary_info = {
+ .name = "qxl-vga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIQXLDevice),
+ .class_init = qxl_primary_class_init,
};
-static PCIDeviceInfo qxl_info_secondary = {
- .qdev.name = "qxl",
- .qdev.desc = "Spice QXL GPU (secondary)",
- .qdev.size = sizeof(PCIQXLDevice),
- .qdev.reset = qxl_reset_handler,
- .qdev.vmsd = &qxl_vmstate,
- .init = qxl_init_secondary,
- .vendor_id = REDHAT_PCI_VENDOR_ID,
- .device_id = QXL_DEVICE_ID_STABLE,
- .class_id = PCI_CLASS_DISPLAY_OTHER,
- .qdev.props = qxl_properties,
+static void qxl_secondary_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = qxl_init_secondary;
+ k->vendor_id = REDHAT_PCI_VENDOR_ID;
+ k->device_id = QXL_DEVICE_ID_STABLE;
+ k->class_id = PCI_CLASS_DISPLAY_OTHER;
+ dc->desc = "Spice QXL GPU (secondary)";
+ dc->reset = qxl_reset_handler;
+ dc->vmsd = &qxl_vmstate;
+ dc->props = qxl_properties;
+}
+
+static TypeInfo qxl_secondary_info = {
+ .name = "qxl",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIQXLDevice),
+ .class_init = qxl_secondary_class_init,
};
static void qxl_register(void)
{
- pci_qdev_register(&qxl_info_primary);
- pci_qdev_register(&qxl_info_secondary);
+ type_register_static(&qxl_primary_info);
+ type_register_static(&qxl_secondary_info);
}
device_init(qxl_register);
diff --git a/hw/realview.c b/hw/realview.c
index 3f35118f21..821e627560 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -82,15 +82,23 @@ static int realview_i2c_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo realview_i2c_info = {
- .init = realview_i2c_init,
- .qdev.name = "realview_i2c",
- .qdev.size = sizeof(RealViewI2CState),
+static void realview_i2c_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = realview_i2c_init;
+}
+
+static TypeInfo realview_i2c_info = {
+ .name = "realview_i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RealViewI2CState),
+ .class_init = realview_i2c_class_init,
};
static void realview_register_devices(void)
{
- sysbus_register_withprop(&realview_i2c_info);
+ type_register_static(&realview_i2c_info);
}
/* Board init. */
@@ -227,6 +235,8 @@ static void realview_init(ram_addr_t ram_size,
for (n = 0; n < smp_cpus; n++) {
sysbus_connect_irq(busdev, n, cpu_irq[n]);
}
+ sysbus_create_varargs("l2x0", realview_binfo.smp_priv_base + 0x2000,
+ NULL);
} else {
uint32_t gic_addr = is_pb ? 0x1e000000 : 0x10040000;
/* For now just create the nIRQ GIC, and ignore the others. */
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 8c4d509ee7..4121502c7b 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,7 +9,6 @@
#include "sysbus.h"
-#define GIC_NIRQ 96
#define NCPU 1
/* Only a single "CPU" interface is present. */
@@ -37,16 +36,33 @@ static int realview_gic_init(SysBusDevice *dev)
{
RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
- gic_init(&s->gic);
+ /* The GICs on the RealView boards have a fixed nonconfigurable
+ * number of interrupt lines, so we don't need to expose this as
+ * a qdev property.
+ */
+ gic_init(&s->gic, 96);
realview_gic_map_setup(s);
sysbus_init_mmio(dev, &s->container);
return 0;
}
+static void realview_gic_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = realview_gic_init;
+}
+
+static TypeInfo realview_gic_info = {
+ .name = "realview_gic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RealViewGICState),
+ .class_init = realview_gic_class_init,
+};
+
static void realview_gic_register_devices(void)
{
- sysbus_register_dev("realview_gic", sizeof(RealViewGICState),
- realview_gic_init);
+ type_register_static(&realview_gic_info);
}
device_init(realview_gic_register_devices)
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 0ae9f5774b..1668390e1f 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3478,7 +3478,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
s->cplus_txbuffer = NULL;
@@ -3494,27 +3494,38 @@ static int pci_rtl8139_init(PCIDevice *dev)
return 0;
}
-static PCIDeviceInfo rtl8139_info = {
- .qdev.name = "rtl8139",
- .qdev.size = sizeof(RTL8139State),
- .qdev.reset = rtl8139_reset,
- .qdev.vmsd = &vmstate_rtl8139,
- .init = pci_rtl8139_init,
- .exit = pci_rtl8139_uninit,
- .romfile = "pxe-rtl8139.rom",
- .vendor_id = PCI_VENDOR_ID_REALTEK,
- .device_id = PCI_DEVICE_ID_REALTEK_8139,
- .revision = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(RTL8139State, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property rtl8139_properties[] = {
+ DEFINE_NIC_PROPERTIES(RTL8139State, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtl8139_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_rtl8139_init;
+ k->exit = pci_rtl8139_uninit;
+ k->romfile = "pxe-rtl8139.rom";
+ k->vendor_id = PCI_VENDOR_ID_REALTEK;
+ k->device_id = PCI_DEVICE_ID_REALTEK_8139;
+ k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = rtl8139_reset;
+ dc->vmsd = &vmstate_rtl8139;
+ dc->props = rtl8139_properties;
+}
+
+static TypeInfo rtl8139_info = {
+ .name = "rtl8139",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(RTL8139State),
+ .class_init = rtl8139_class_init,
};
static void rtl8139_register_devices(void)
{
- pci_qdev_register(&rtl8139_info);
+ type_register_static(&rtl8139_info);
}
device_init(rtl8139_register_devices)
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index 2efea9f184..49140f8a9e 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -50,12 +50,6 @@ struct BusInfo s390_virtio_bus_info = {
.size = sizeof(VirtIOS390Bus),
};
-typedef struct {
- DeviceInfo qdev;
- int (*init)(VirtIOS390Device *dev);
-} VirtIOS390DeviceInfo;
-
-
static const VirtIOBindings virtio_s390_bindings;
static ram_addr_t s390_virtio_device_num_vq(VirtIOS390Device *dev);
@@ -343,69 +337,108 @@ static const VirtIOBindings virtio_s390_bindings = {
.get_features = virtio_s390_get_features,
};
-static VirtIOS390DeviceInfo s390_virtio_net = {
- .init = s390_virtio_net_init,
- .qdev.name = "virtio-net-s390",
- .qdev.alias = "virtio-net",
- .qdev.size = sizeof(VirtIOS390Device),
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
- DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
- net.txtimer, TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
- net.txburst, TX_BURST),
- DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property s390_virtio_net_properties[] = {
+ DEFINE_NIC_PROPERTIES(VirtIOS390Device, nic),
+ DEFINE_PROP_UINT32("x-txtimer", VirtIOS390Device,
+ net.txtimer, TX_TIMER_INTERVAL),
+ DEFINE_PROP_INT32("x-txburst", VirtIOS390Device,
+ net.txburst, TX_BURST),
+ DEFINE_PROP_STRING("tx", VirtIOS390Device, net.tx),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_net_init;
+ dc->props = s390_virtio_net_properties;
+}
+
+static TypeInfo s390_virtio_net = {
+ .name = "virtio-net-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = s390_virtio_net_class_init,
+};
+
+static Property s390_virtio_blk_properties[] = {
+ DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
+ DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_blk_init;
+ dc->props = s390_virtio_blk_properties;
+}
+
+static TypeInfo s390_virtio_blk = {
+ .name = "virtio-blk-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = s390_virtio_blk_class_init,
};
-static VirtIOS390DeviceInfo s390_virtio_blk = {
- .init = s390_virtio_blk_init,
- .qdev.name = "virtio-blk-s390",
- .qdev.alias = "virtio-blk",
- .qdev.size = sizeof(VirtIOS390Device),
- .qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
- DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property s390_virtio_serial_properties[] = {
+ DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
+ serial.max_virtserial_ports, 31),
+ DEFINE_PROP_END_OF_LIST(),
};
-static VirtIOS390DeviceInfo s390_virtio_serial = {
- .init = s390_virtio_serial_init,
- .qdev.name = "virtio-serial-s390",
- .qdev.alias = "virtio-serial",
- .qdev.size = sizeof(VirtIOS390Device),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("max_ports", VirtIOS390Device,
- serial.max_virtserial_ports, 31),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_serial_init;
+ dc->props = s390_virtio_serial_properties;
+}
+
+static TypeInfo s390_virtio_serial = {
+ .name = "virtio-serial-s390",
+ .parent = TYPE_VIRTIO_S390_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = s390_virtio_serial_class_init,
};
-static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info)
+static int s390_virtio_busdev_init(DeviceState *dev)
{
- VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info;
VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
+ VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
return _info->init(_dev);
}
-static void s390_virtio_bus_register_withprop(VirtIOS390DeviceInfo *info)
+static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
{
- info->qdev.init = s390_virtio_busdev_init;
- info->qdev.bus_info = &s390_virtio_bus_info;
- info->qdev.unplug = qdev_simple_unplug_cb;
+ DeviceClass *dc = DEVICE_CLASS(klass);
- assert(info->qdev.size >= sizeof(VirtIOS390Device));
- qdev_register(&info->qdev);
+ dc->init = s390_virtio_busdev_init;
+ dc->bus_info = &s390_virtio_bus_info;
+ dc->unplug = qdev_simple_unplug_cb;
}
+static TypeInfo virtio_s390_device_info = {
+ .name = TYPE_VIRTIO_S390_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VirtIOS390Device),
+ .class_init = virtio_s390_device_class_init,
+ .class_size = sizeof(VirtIOS390DeviceClass),
+ .abstract = true,
+};
+
static void s390_virtio_register(void)
{
- s390_virtio_bus_register_withprop(&s390_virtio_serial);
- s390_virtio_bus_register_withprop(&s390_virtio_blk);
- s390_virtio_bus_register_withprop(&s390_virtio_net);
+ type_register_static(&virtio_s390_device_info);
+ type_register_static(&s390_virtio_serial);
+ type_register_static(&s390_virtio_blk);
+ type_register_static(&s390_virtio_net);
}
device_init(s390_virtio_register);
@@ -419,16 +452,25 @@ static int s390_virtio_bridge_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo s390_virtio_bridge_info = {
- .init = s390_virtio_bridge_init,
- .qdev.name = "s390-virtio-bridge",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
+static void s390_virtio_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = s390_virtio_bridge_init;
+ dc->no_user = 1;
+}
+
+static TypeInfo s390_virtio_bridge_info = {
+ .name = "s390-virtio-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = s390_virtio_bridge_class_init,
};
static void s390_virtio_register_devices(void)
{
- sysbus_register_withprop(&s390_virtio_bridge_info);
+ type_register_static(&s390_virtio_bridge_info);
}
device_init(s390_virtio_register_devices)
diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h
index d02a90709d..b5e59b7d4b 100644
--- a/hw/s390-virtio-bus.h
+++ b/hw/s390-virtio-bus.h
@@ -40,7 +40,22 @@
#define VIRTIO_PARAM_CONFIG_CHANGED 0x1
#define VIRTIO_PARAM_DEV_ADD 0x2
-typedef struct VirtIOS390Device {
+#define TYPE_VIRTIO_S390_DEVICE "virtio-s390-device"
+#define VIRTIO_S390_DEVICE(obj) \
+ OBJECT_CHECK(VirtIOS390Device, (obj), TYPE_VIRTIO_S390_DEVICE)
+#define VIRTIO_S390_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VirtIOS390DeviceClass, (klass), TYPE_VIRTIO_S390_DEVICE)
+#define VIRTIO_S390_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VirtIOS390DeviceClass, (obj), TYPE_VIRTIO_S390_DEVICE)
+
+typedef struct VirtIOS390Device VirtIOS390Device;
+
+typedef struct VirtIOS390DeviceClass {
+ DeviceClass qdev;
+ int (*init)(VirtIOS390Device *dev);
+} VirtIOS390DeviceClass;
+
+struct VirtIOS390Device {
DeviceState qdev;
ram_addr_t dev_offs;
ram_addr_t feat_offs;
@@ -52,7 +67,7 @@ typedef struct VirtIOS390Device {
uint32_t host_features;
virtio_serial_conf serial;
virtio_net_conf net;
-} VirtIOS390Device;
+};
typedef struct VirtIOS390Bus {
BusState bus;
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index 2210b8ac7e..51123a7535 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -317,7 +317,6 @@ static QEMUMachine s390_machine = {
.no_serial = 1,
.no_parallel = 1,
.use_virtcon = 1,
- .no_vga = 1,
.max_cpus = 255,
.is_default = 1,
};
diff --git a/hw/sb16.c b/hw/sb16.c
index 887b32e794..db8929b98e 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -1289,55 +1289,55 @@ static const VMStateDescription vmstate_sb16 = {
.minimum_version_id_old = 1,
.post_load = sb16_post_load,
.fields = (VMStateField []) {
- VMSTATE_UINT32(irq, SB16State),
- VMSTATE_UINT32(dma, SB16State),
- VMSTATE_UINT32(hdma, SB16State),
- VMSTATE_UINT32(port, SB16State),
- VMSTATE_UINT32(ver, SB16State),
- VMSTATE_INT32(in_index, SB16State),
- VMSTATE_INT32(out_data_len, SB16State),
- VMSTATE_INT32(fmt_stereo, SB16State),
- VMSTATE_INT32(fmt_signed, SB16State),
- VMSTATE_INT32(fmt_bits, SB16State),
- VMSTATE_UINT32(fmt, SB16State),
- VMSTATE_INT32(dma_auto, SB16State),
- VMSTATE_INT32(block_size, SB16State),
- VMSTATE_INT32(fifo, SB16State),
- VMSTATE_INT32(freq, SB16State),
- VMSTATE_INT32(time_const, SB16State),
- VMSTATE_INT32(speaker, SB16State),
- VMSTATE_INT32(needed_bytes, SB16State),
- VMSTATE_INT32(cmd, SB16State),
- VMSTATE_INT32(use_hdma, SB16State),
- VMSTATE_INT32(highspeed, SB16State),
- VMSTATE_INT32(can_write, SB16State),
- VMSTATE_INT32(v2x6, SB16State),
-
- VMSTATE_UINT8(csp_param, SB16State),
- VMSTATE_UINT8(csp_value, SB16State),
- VMSTATE_UINT8(csp_mode, SB16State),
- VMSTATE_UINT8(csp_param, SB16State),
- VMSTATE_BUFFER(csp_regs, SB16State),
- VMSTATE_UINT8(csp_index, SB16State),
- VMSTATE_BUFFER(csp_reg83, SB16State),
- VMSTATE_INT32(csp_reg83r, SB16State),
- VMSTATE_INT32(csp_reg83w, SB16State),
-
- VMSTATE_BUFFER(in2_data, SB16State),
- VMSTATE_BUFFER(out_data, SB16State),
- VMSTATE_UINT8(test_reg, SB16State),
- VMSTATE_UINT8(last_read_byte, SB16State),
-
- VMSTATE_INT32(nzero, SB16State),
- VMSTATE_INT32(left_till_irq, SB16State),
- VMSTATE_INT32(dma_running, SB16State),
- VMSTATE_INT32(bytes_per_second, SB16State),
- VMSTATE_INT32(align, SB16State),
-
- VMSTATE_INT32(mixer_nreg, SB16State),
- VMSTATE_BUFFER(mixer_regs, SB16State),
-
- VMSTATE_END_OF_LIST()
+ VMSTATE_UINT32 (irq, SB16State),
+ VMSTATE_UINT32 (dma, SB16State),
+ VMSTATE_UINT32 (hdma, SB16State),
+ VMSTATE_UINT32 (port, SB16State),
+ VMSTATE_UINT32 (ver, SB16State),
+ VMSTATE_INT32 (in_index, SB16State),
+ VMSTATE_INT32 (out_data_len, SB16State),
+ VMSTATE_INT32 (fmt_stereo, SB16State),
+ VMSTATE_INT32 (fmt_signed, SB16State),
+ VMSTATE_INT32 (fmt_bits, SB16State),
+ VMSTATE_UINT32 (fmt, SB16State),
+ VMSTATE_INT32 (dma_auto, SB16State),
+ VMSTATE_INT32 (block_size, SB16State),
+ VMSTATE_INT32 (fifo, SB16State),
+ VMSTATE_INT32 (freq, SB16State),
+ VMSTATE_INT32 (time_const, SB16State),
+ VMSTATE_INT32 (speaker, SB16State),
+ VMSTATE_INT32 (needed_bytes, SB16State),
+ VMSTATE_INT32 (cmd, SB16State),
+ VMSTATE_INT32 (use_hdma, SB16State),
+ VMSTATE_INT32 (highspeed, SB16State),
+ VMSTATE_INT32 (can_write, SB16State),
+ VMSTATE_INT32 (v2x6, SB16State),
+
+ VMSTATE_UINT8 (csp_param, SB16State),
+ VMSTATE_UINT8 (csp_value, SB16State),
+ VMSTATE_UINT8 (csp_mode, SB16State),
+ VMSTATE_UINT8 (csp_param, SB16State),
+ VMSTATE_BUFFER (csp_regs, SB16State),
+ VMSTATE_UINT8 (csp_index, SB16State),
+ VMSTATE_BUFFER (csp_reg83, SB16State),
+ VMSTATE_INT32 (csp_reg83r, SB16State),
+ VMSTATE_INT32 (csp_reg83w, SB16State),
+
+ VMSTATE_BUFFER (in2_data, SB16State),
+ VMSTATE_BUFFER (out_data, SB16State),
+ VMSTATE_UINT8 (test_reg, SB16State),
+ VMSTATE_UINT8 (last_read_byte, SB16State),
+
+ VMSTATE_INT32 (nzero, SB16State),
+ VMSTATE_INT32 (left_till_irq, SB16State),
+ VMSTATE_INT32 (dma_running, SB16State),
+ VMSTATE_INT32 (bytes_per_second, SB16State),
+ VMSTATE_INT32 (align, SB16State),
+
+ VMSTATE_INT32 (mixer_nreg, SB16State),
+ VMSTATE_BUFFER (mixer_regs, SB16State),
+
+ VMSTATE_END_OF_LIST ()
}
};
@@ -1349,7 +1349,7 @@ static const MemoryRegionPortio sb16_ioport_list[] = {
{ 10, 1, 1, .read = dsp_read },
{ 12, 1, 1, .write = dsp_write },
{ 12, 4, 1, .read = dsp_read },
- PORTIO_END_OF_LIST(),
+ PORTIO_END_OF_LIST (),
};
@@ -1391,24 +1391,34 @@ int SB16_init (ISABus *bus)
return 0;
}
-static ISADeviceInfo sb16_info = {
- .qdev.name = "sb16",
- .qdev.desc = "Creative Sound Blaster 16",
- .qdev.size = sizeof (SB16State),
- .qdev.vmsd = &vmstate_sb16,
- .init = sb16_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */
- DEFINE_PROP_HEX32 ("iobase", SB16State, port, 0x220),
- DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
- DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
- DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
- DEFINE_PROP_END_OF_LIST (),
- },
+static Property sb16_properties[] = {
+ DEFINE_PROP_HEX32 ("version", SB16State, ver, 0x0405), /* 4.5 */
+ DEFINE_PROP_HEX32 ("iobase", SB16State, port, 0x220),
+ DEFINE_PROP_UINT32 ("irq", SB16State, irq, 5),
+ DEFINE_PROP_UINT32 ("dma", SB16State, dma, 1),
+ DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5),
+ DEFINE_PROP_END_OF_LIST (),
+};
+
+static void sb16_class_initfn (ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS (klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS (klass);
+ ic->init = sb16_initfn;
+ dc->desc = "Creative Sound Blaster 16";
+ dc->vmsd = &vmstate_sb16;
+ dc->props = sb16_properties;
+}
+
+static TypeInfo sb16_info = {
+ .name = "sb16",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof (SB16State),
+ .class_init = sb16_class_initfn,
};
static void sb16_register (void)
{
- isa_qdev_register (&sb16_info);
+ type_register_static (&sb16_info);
}
device_init (sb16_register)
diff --git a/hw/sbi.c b/hw/sbi.c
index 8965a71771..847a4dde84 100644
--- a/hw/sbi.c
+++ b/hw/sbi.c
@@ -131,17 +131,26 @@ static int sbi_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo sbi_info = {
- .init = sbi_init1,
- .qdev.name = "sbi",
- .qdev.size = sizeof(SBIState),
- .qdev.vmsd = &vmstate_sbi,
- .qdev.reset = sbi_reset,
+static void sbi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sbi_init1;
+ dc->reset = sbi_reset;
+ dc->vmsd = &vmstate_sbi;
+}
+
+static TypeInfo sbi_info = {
+ .name = "sbi",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SBIState),
+ .class_init = sbi_class_init,
};
static void sbi_register_devices(void)
{
- sysbus_register_withprop(&sbi_info);
+ type_register_static(&sbi_info);
}
device_init(sbi_register_devices)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 64e709ee9f..0ee50a8360 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -23,6 +23,42 @@ static struct BusInfo scsi_bus_info = {
};
static int next_scsi_bus;
+static int scsi_device_init(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->init) {
+ return sc->init(s);
+ }
+ return 0;
+}
+
+static void scsi_device_destroy(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->destroy) {
+ sc->destroy(s);
+ }
+}
+
+static SCSIRequest *scsi_device_alloc_req(SCSIDevice *s, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->alloc_req) {
+ return sc->alloc_req(s, tag, lun, buf, hba_private);
+ }
+
+ return NULL;
+}
+
+static void scsi_device_unit_attention_reported(SCSIDevice *s)
+{
+ SCSIDeviceClass *sc = SCSI_DEVICE_GET_CLASS(s);
+ if (sc->unit_attention_reported) {
+ sc->unit_attention_reported(s);
+ }
+}
+
/* Create a scsi bus, and attach devices to it. */
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
{
@@ -79,10 +115,9 @@ static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
}
}
-static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int scsi_qdev_init(DeviceState *qdev)
{
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
SCSIDevice *d;
int rc = -1;
@@ -126,9 +161,8 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
}
}
- dev->info = info;
QTAILQ_INIT(&dev->requests);
- rc = dev->info->init(dev);
+ rc = scsi_device_init(dev);
if (rc == 0) {
dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
dev);
@@ -140,26 +174,15 @@ err:
static int scsi_qdev_exit(DeviceState *qdev)
{
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->vmsentry) {
qemu_del_vm_change_state_handler(dev->vmsentry);
}
- if (dev->info->destroy) {
- dev->info->destroy(dev);
- }
+ scsi_device_destroy(dev);
return 0;
}
-void scsi_qdev_register(SCSIDeviceInfo *info)
-{
- info->qdev.bus_info = &scsi_bus_info;
- info->qdev.init = scsi_qdev_init;
- info->qdev.unplug = qdev_simple_unplug_cb;
- info->qdev.exit = scsi_qdev_exit;
- qdev_register(&info->qdev);
-}
-
/* handle legacy '-drive if=scsi,...' cmd line args */
SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
int unit, bool removable, int bootindex)
@@ -182,7 +205,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
}
if (qdev_init(dev) < 0)
return NULL;
- return DO_UPCAST(SCSIDevice, qdev, dev);
+ return SCSI_DEVICE(dev);
}
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
@@ -278,7 +301,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
found_lun0 = false;
n = 0;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == 0) {
@@ -300,7 +323,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
stl_be_p(&r->buf, n);
i = found_lun0 ? 8 : 16;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
store_lun(&r->buf[i], dev->lun);
@@ -398,9 +421,7 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
MIN(req->cmd.xfer, sizeof r->buf),
(req->cmd.buf[1] & 1) == 0);
if (r->req.dev->sense_is_ua) {
- if (r->req.dev->info->unit_attention_reported) {
- r->req.dev->info->unit_attention_reported(req->dev);
- }
+ scsi_device_unit_attention_reported(req->dev);
r->req.dev->sense_len = 0;
r->req.dev->sense_is_ua = false;
}
@@ -507,7 +528,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
hba_private);
} else {
- req = d->info->alloc_req(d, tag, lun, buf, hba_private);
+ req = scsi_device_alloc_req(d, tag, lun, buf, hba_private);
}
}
@@ -597,9 +618,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
* Here we handle unit attention clearing for UA_INTLCK_CTRL == 00b.
*/
if (req->dev->sense_is_ua) {
- if (req->dev->info->unit_attention_reported) {
- req->dev->info->unit_attention_reported(req->dev);
- }
+ scsi_device_unit_attention_reported(req->dev);
req->dev->sense_len = 0;
req->dev->sense_is_ua = false;
}
@@ -1367,7 +1386,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
static char *scsibus_get_fw_dev_path(DeviceState *dev)
{
- SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
+ SCSIDevice *d = SCSI_DEVICE(dev);
char path[100];
snprintf(path, sizeof(path), "channel@%x/%s@%x,%x", d->channel,
@@ -1382,7 +1401,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
SCSIDevice *target_dev = NULL;
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
- SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
if (dev->channel == channel && dev->id == id) {
if (dev->lun == lun) {
@@ -1393,3 +1412,28 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
}
return target_dev;
}
+
+static void scsi_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->bus_info = &scsi_bus_info;
+ k->init = scsi_qdev_init;
+ k->unplug = qdev_simple_unplug_cb;
+ k->exit = scsi_qdev_exit;
+}
+
+static TypeInfo scsi_device_type_info = {
+ .name = TYPE_SCSI_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SCSIDevice),
+ .abstract = true,
+ .class_size = sizeof(SCSIDeviceClass),
+ .class_init = scsi_device_class_init,
+};
+
+static void scsi_register_devices(void)
+{
+ type_register_static(&scsi_device_type_info);
+}
+
+device_init(scsi_register_devices);
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 5d8bf53586..399e51e494 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -391,9 +391,6 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
}
l = strlen(s->serial);
- if (l > req->cmd.xfer) {
- l = req->cmd.xfer;
- }
if (l > 20) {
l = 20;
}
@@ -1002,9 +999,6 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
outbuf[0] = ((buflen - 2) >> 8) & 0xff;
outbuf[1] = (buflen - 2) & 0xff;
}
- if (buflen > r->req.cmd.xfer) {
- buflen = r->req.cmd.xfer;
- }
return buflen;
}
@@ -1038,9 +1032,6 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
default:
return -1;
}
- if (toclen > req->cmd.xfer) {
- toclen = req->cmd.xfer;
- }
return toclen;
}
@@ -1251,6 +1242,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
return -1;
}
+ buflen = MIN(buflen, req->cmd.xfer);
return buflen;
not_ready:
@@ -1720,75 +1712,124 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
DEFINE_PROP_STRING("ver", SCSIDiskState, version), \
DEFINE_PROP_STRING("serial", SCSIDiskState, serial)
-static SCSIDeviceInfo scsi_disk_info[] = {
- {
- .qdev.name = "scsi-hd",
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI disk",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_hd_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- }
- },{
- .qdev.name = "scsi-cd",
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI CD-ROM",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_cd_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property scsi_hd_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_hd_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_hd_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+ dc->fw_name = "disk";
+ dc->desc = "virtual SCSI disk";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_hd_properties;
+}
+
+static TypeInfo scsi_hd_info = {
+ .name = "scsi-hd",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_hd_class_initfn,
+};
+
+static Property scsi_cd_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_cd_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_cd_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+ dc->fw_name = "disk";
+ dc->desc = "virtual SCSI CD-ROM";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_cd_properties;
+}
+
+static TypeInfo scsi_cd_info = {
+ .name = "scsi-cd",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_cd_class_initfn,
+};
+
#ifdef __linux__
- },{
- .qdev.name = "scsi-block",
- .qdev.fw_name = "disk",
- .qdev.desc = "SCSI block device passthrough",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_block_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_block_new_request,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property scsi_block_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_block_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_block_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_block_new_request;
+ dc->fw_name = "disk";
+ dc->desc = "SCSI block device passthrough";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_block_properties;
+}
+
+static TypeInfo scsi_block_info = {
+ .name = "scsi-block",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_block_class_initfn,
+};
#endif
- },{
- .qdev.name = "scsi-disk", /* legacy -device scsi-disk */
- .qdev.fw_name = "disk",
- .qdev.desc = "virtual SCSI disk or CD-ROM (legacy)",
- .qdev.size = sizeof(SCSIDiskState),
- .qdev.reset = scsi_disk_reset,
- .init = scsi_disk_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .unit_attention_reported = scsi_disk_unit_attention_reported,
- .qdev.props = (Property[]) {
- DEFINE_SCSI_DISK_PROPERTIES(),
- DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- }
- }
+
+static Property scsi_disk_properties[] = {
+ DEFINE_SCSI_DISK_PROPERTIES(),
+ DEFINE_PROP_BIT("removable", SCSIDiskState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
};
-static void scsi_disk_register_devices(void)
+static void scsi_disk_class_initfn(ObjectClass *klass, void *data)
{
- int i;
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_disk_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ sc->unit_attention_reported = scsi_disk_unit_attention_reported;
+ dc->fw_name = "disk";
+ dc->desc = "virtual SCSI disk or CD-ROM (legacy)";
+ dc->reset = scsi_disk_reset;
+ dc->props = scsi_disk_properties;
+}
- for (i = 0; i < ARRAY_SIZE(scsi_disk_info); i++) {
- scsi_qdev_register(&scsi_disk_info[i]);
- }
+static TypeInfo scsi_disk_info = {
+ .name = "scsi-disk",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDiskState),
+ .class_init = scsi_disk_class_initfn,
+};
+
+static void scsi_disk_register_devices(void)
+{
+ type_register_static(&scsi_hd_info);
+ type_register_static(&scsi_cd_info);
+#ifdef __linux__
+ type_register_static(&scsi_block_info);
+#endif
+ type_register_static(&scsi_disk_info);
}
device_init(scsi_disk_register_devices)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 0aebcddf6e..4859212734 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -357,7 +357,7 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
static void scsi_generic_reset(DeviceState *dev)
{
- SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
+ SCSIDevice *s = SCSI_DEVICE(dev);
scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
@@ -457,24 +457,35 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
return req;
}
-static SCSIDeviceInfo scsi_generic_info = {
- .qdev.name = "scsi-generic",
- .qdev.fw_name = "disk",
- .qdev.desc = "pass through generic scsi device (/dev/sg*)",
- .qdev.size = sizeof(SCSIDevice),
- .qdev.reset = scsi_generic_reset,
- .init = scsi_generic_initfn,
- .destroy = scsi_destroy,
- .alloc_req = scsi_new_request,
- .qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property scsi_generic_properties[] = {
+ DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scsi_generic_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass);
+
+ sc->init = scsi_generic_initfn;
+ sc->destroy = scsi_destroy;
+ sc->alloc_req = scsi_new_request;
+ dc->fw_name = "disk";
+ dc->desc = "pass through generic scsi device (/dev/sg*)";
+ dc->reset = scsi_generic_reset;
+ dc->props = scsi_generic_properties;
+}
+
+static TypeInfo scsi_generic_info = {
+ .name = "scsi-generic",
+ .parent = TYPE_SCSI_DEVICE,
+ .instance_size = sizeof(SCSIDevice),
+ .class_init = scsi_generic_class_initfn,
};
static void scsi_generic_register_devices(void)
{
- scsi_qdev_register(&scsi_generic_info);
+ type_register_static(&scsi_generic_info);
}
device_init(scsi_generic_register_devices)
diff --git a/hw/scsi.h b/hw/scsi.h
index ab6e952327..dc72b6fc1e 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -13,7 +13,6 @@ typedef struct SCSIBus SCSIBus;
typedef struct SCSIBusInfo SCSIBusInfo;
typedef struct SCSICommand SCSICommand;
typedef struct SCSIDevice SCSIDevice;
-typedef struct SCSIDeviceInfo SCSIDeviceInfo;
typedef struct SCSIRequest SCSIRequest;
typedef struct SCSIReqOps SCSIReqOps;
@@ -58,6 +57,23 @@ struct SCSIRequest {
QTAILQ_ENTRY(SCSIRequest) next;
};
+#define TYPE_SCSI_DEVICE "scsi-device"
+#define SCSI_DEVICE(obj) \
+ OBJECT_CHECK(SCSIDevice, (obj), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SCSIDeviceClass, (klass), TYPE_SCSI_DEVICE)
+#define SCSI_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SCSIDeviceClass, (obj), TYPE_SCSI_DEVICE)
+
+typedef struct SCSIDeviceClass {
+ DeviceClass parent_class;
+ int (*init)(SCSIDevice *dev);
+ void (*destroy)(SCSIDevice *s);
+ SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private);
+ void (*unit_attention_reported)(SCSIDevice *s);
+} SCSIDeviceClass;
+
struct SCSIDevice
{
DeviceState qdev;
@@ -65,7 +81,6 @@ struct SCSIDevice
QEMUBH *bh;
uint32_t id;
BlockConf conf;
- SCSIDeviceInfo *info;
SCSISense unit_attention;
bool sense_is_ua;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
@@ -93,16 +108,6 @@ struct SCSIReqOps {
uint8_t *(*get_buf)(SCSIRequest *req);
};
-typedef int (*scsi_qdev_initfn)(SCSIDevice *dev);
-struct SCSIDeviceInfo {
- DeviceInfo qdev;
- scsi_qdev_initfn init;
- void (*destroy)(SCSIDevice *s);
- SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
- uint8_t *buf, void *hba_private);
- void (*unit_attention_reported)(SCSIDevice *s);
-};
-
struct SCSIBusInfo {
int tcq;
int max_channel, max_target, max_lun;
@@ -120,7 +125,6 @@ struct SCSIBus {
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
-void scsi_qdev_register(SCSIDeviceInfo *info);
static inline SCSIBus *scsi_bus_from_device(SCSIDevice *d)
{
diff --git a/hw/serial.c b/hw/serial.c
index d35c7a9207..82917e24d7 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -879,23 +879,33 @@ SerialState *serial_mm_init(MemoryRegion *address_space,
return s;
}
-static ISADeviceInfo serial_isa_info = {
- .qdev.name = "isa-serial",
- .qdev.size = sizeof(ISASerialState),
- .qdev.vmsd = &vmstate_isa_serial,
- .init = serial_isa_initfn,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
- DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1),
- DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
- DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property serial_isa_properties[] = {
+ DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
+ DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1),
+ DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1),
+ DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void serial_isa_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = serial_isa_initfn;
+ dc->vmsd = &vmstate_isa_serial;
+ dc->props = serial_isa_properties;
+}
+
+static TypeInfo serial_isa_info = {
+ .name = "isa-serial",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISASerialState),
+ .class_init = serial_isa_class_initfn,
};
static void serial_register_devices(void)
{
- isa_qdev_register(&serial_isa_info);
+ type_register_static(&serial_isa_info);
}
device_init(serial_register_devices)
diff --git a/hw/sga.c b/hw/sga.c
index 7ef750adf6..b08e3c5aea 100644
--- a/hw/sga.c
+++ b/hw/sga.c
@@ -35,22 +35,29 @@ typedef struct ISAGAState {
ISADevice dev;
} ISASGAState;
-static int isa_cirrus_vga_initfn(ISADevice *dev)
+static int sga_initfn(ISADevice *dev)
{
rom_add_vga(SGABIOS_FILENAME);
return 0;
}
+static void sga_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = sga_initfn;
+ dc->desc = "Serial Graphics Adapter";
+}
-static ISADeviceInfo sga_info = {
- .qdev.name = "sga",
- .qdev.desc = "Serial Graphics Adapter",
- .qdev.size = sizeof(ISASGAState),
- .init = isa_cirrus_vga_initfn,
+static TypeInfo sga_info = {
+ .name = "sga",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISASGAState),
+ .class_init = sga_class_initfn,
};
static void sga_register(void)
{
- isa_qdev_register(&sga_info);
+ type_register_static(&sga_info);
}
device_init(sga_register);
diff --git a/hw/sh_pci.c b/hw/sh_pci.c
index d4d028d811..4234d935e7 100644
--- a/hw/sh_pci.c
+++ b/hw/sh_pci.c
@@ -110,7 +110,7 @@ static void sh_pci_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(pic[irq_num], level);
}
-static int sh_pci_init_device(SysBusDevice *dev)
+static int sh_pci_device_init(SysBusDevice *dev)
{
SHPCIState *s;
int i;
@@ -147,19 +147,40 @@ static int sh_pci_host_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo sh_pci_host_info = {
- .qdev.name = "sh_pci_host",
- .qdev.size = sizeof(PCIDevice),
- .init = sh_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_HITACHI,
- .device_id = PCI_DEVICE_ID_HITACHI_SH7751R,
+static void sh_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = sh_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_HITACHI;
+ k->device_id = PCI_DEVICE_ID_HITACHI_SH7751R;
+}
+
+static TypeInfo sh_pci_host_info = {
+ .name = "sh_pci_host",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = sh_pci_host_class_init,
+};
+
+static void sh_pci_device_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = sh_pci_device_init;
+}
+
+static TypeInfo sh_pci_device_info = {
+ .name = "sh_pci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SHPCIState),
+ .class_init = sh_pci_device_class_init,
};
static void sh_pci_register_devices(void)
{
- sysbus_register_dev("sh_pci", sizeof(SHPCIState),
- sh_pci_init_device);
- pci_qdev_register(&sh_pci_host_info);
+ type_register_static(&sh_pci_device_info);
+ type_register_static(&sh_pci_host_info);
}
device_init(sh_pci_register_devices)
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index 9925e6460b..e3701c75d2 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -446,17 +446,26 @@ static int slavio_intctl_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo slavio_intctl_info = {
- .init = slavio_intctl_init1,
- .qdev.name = "slavio_intctl",
- .qdev.size = sizeof(SLAVIO_INTCTLState),
- .qdev.vmsd = &vmstate_intctl,
- .qdev.reset = slavio_intctl_reset,
+static void slavio_intctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = slavio_intctl_init1;
+ dc->reset = slavio_intctl_reset;
+ dc->vmsd = &vmstate_intctl;
+}
+
+static TypeInfo slavio_intctl_info = {
+ .name = "slavio_intctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SLAVIO_INTCTLState),
+ .class_init = slavio_intctl_class_init,
};
static void slavio_intctl_register_devices(void)
{
- sysbus_register_withprop(&slavio_intctl_info);
+ type_register_static(&slavio_intctl_info);
}
device_init(slavio_intctl_register_devices)
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index 484301c48a..5a025186af 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -468,24 +468,41 @@ static int slavio_misc_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo slavio_misc_info = {
- .init = slavio_misc_init1,
- .qdev.name = "slavio_misc",
- .qdev.size = sizeof(MiscState),
- .qdev.vmsd = &vmstate_misc,
- .qdev.reset = slavio_misc_reset,
+static void slavio_misc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = slavio_misc_init1;
+ dc->reset = slavio_misc_reset;
+ dc->vmsd = &vmstate_misc;
+}
+
+static TypeInfo slavio_misc_info = {
+ .name = "slavio_misc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MiscState),
+ .class_init = slavio_misc_class_init,
};
-static SysBusDeviceInfo apc_info = {
- .init = apc_init1,
- .qdev.name = "apc",
- .qdev.size = sizeof(MiscState),
+static void apc_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = apc_init1;
+}
+
+static TypeInfo apc_info = {
+ .name = "apc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(MiscState),
+ .class_init = apc_class_init,
};
static void slavio_misc_register_devices(void)
{
- sysbus_register_withprop(&slavio_misc_info);
- sysbus_register_withprop(&apc_info);
+ type_register_static(&slavio_misc_info);
+ type_register_static(&apc_info);
}
device_init(slavio_misc_register_devices)
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 44b500a5fa..3878f6fa5e 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -404,21 +404,32 @@ static int slavio_timer_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo slavio_timer_info = {
- .init = slavio_timer_init1,
- .qdev.name = "slavio_timer",
- .qdev.size = sizeof(SLAVIO_TIMERState),
- .qdev.vmsd = &vmstate_slavio_timer,
- .qdev.reset = slavio_timer_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property slavio_timer_properties[] = {
+ DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void slavio_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = slavio_timer_init1;
+ dc->reset = slavio_timer_reset;
+ dc->vmsd = &vmstate_slavio_timer;
+ dc->props = slavio_timer_properties;
+}
+
+static TypeInfo slavio_timer_info = {
+ .name = "slavio_timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SLAVIO_TIMERState),
+ .class_init = slavio_timer_class_init,
};
static void slavio_timer_register_devices(void)
{
- sysbus_register_withprop(&slavio_timer_info);
+ type_register_static(&slavio_timer_info);
}
device_init(slavio_timer_register_devices)
diff --git a/hw/sm501.c b/hw/sm501.c
index 09c5894cf9..94c0abf4cb 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -1323,15 +1323,12 @@ static void sm501_draw_crt(SM501State * s)
for (y = 0; y < height; y++) {
int update_hwc = draw_hwc_line ? within_hwc_y_range(s, y, 1) : 0;
int update = full_update || update_hwc;
- ram_addr_t page0 = offset & TARGET_PAGE_MASK;
- ram_addr_t page1 = (offset + width * src_bpp - 1) & TARGET_PAGE_MASK;
- ram_addr_t page;
+ ram_addr_t page0 = offset;
+ ram_addr_t page1 = offset + width * src_bpp - 1;
/* check dirty flags for each line */
- for (page = page0; page <= page1; page += TARGET_PAGE_SIZE)
- if (memory_region_get_dirty(&s->local_mem_region, page,
- DIRTY_MEMORY_VGA))
- update = 1;
+ update = memory_region_get_dirty(&s->local_mem_region, page0, page1,
+ DIRTY_MEMORY_VGA);
/* draw line and change status */
if (update) {
diff --git a/hw/smbus.c b/hw/smbus.c
index ff027c814f..77626f3645 100644
--- a/hw/smbus.c
+++ b/hw/smbus.c
@@ -37,37 +37,38 @@ enum {
static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
{
- SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
DPRINTF("Quick Command %d\n", recv);
- if (t->quick_cmd)
- t->quick_cmd(dev, recv);
+ if (sc->quick_cmd) {
+ sc->quick_cmd(dev, recv);
+ }
}
static void smbus_do_write(SMBusDevice *dev)
{
- SMBusDeviceInfo *t = container_of(dev->i2c.info, SMBusDeviceInfo, i2c);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
if (dev->data_len == 0) {
smbus_do_quick_cmd(dev, 0);
} else if (dev->data_len == 1) {
DPRINTF("Send Byte\n");
- if (t->send_byte) {
- t->send_byte(dev, dev->data_buf[0]);
+ if (sc->send_byte) {
+ sc->send_byte(dev, dev->data_buf[0]);
}
} else {
dev->command = dev->data_buf[0];
DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
- if (t->write_data) {
- t->write_data(dev, dev->command, dev->data_buf + 1,
- dev->data_len - 1);
+ if (sc->write_data) {
+ sc->write_data(dev, dev->command, dev->data_buf + 1,
+ dev->data_len - 1);
}
}
}
-static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
+static void smbus_i2c_event(I2CSlave *s, enum i2c_event event)
{
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+ SMBusDevice *dev = SMBUS_DEVICE(s);
switch (event) {
case I2C_START_SEND:
@@ -148,16 +149,16 @@ static void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
}
}
-static int smbus_i2c_recv(i2c_slave *s)
+static int smbus_i2c_recv(I2CSlave *s)
{
- SMBusDeviceInfo *t = container_of(s->info, SMBusDeviceInfo, i2c);
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+ SMBusDevice *dev = SMBUS_DEVICE(s);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
int ret;
switch (dev->mode) {
case SMBUS_RECV_BYTE:
- if (t->receive_byte) {
- ret = t->receive_byte(dev);
+ if (sc->receive_byte) {
+ ret = sc->receive_byte(dev);
} else {
ret = 0;
}
@@ -165,8 +166,8 @@ static int smbus_i2c_recv(i2c_slave *s)
dev->mode = SMBUS_DONE;
break;
case SMBUS_READ_DATA:
- if (t->read_data) {
- ret = t->read_data(dev, dev->command, dev->data_len);
+ if (sc->read_data) {
+ ret = sc->read_data(dev, dev->command, dev->data_len);
dev->data_len++;
} else {
ret = 0;
@@ -182,9 +183,9 @@ static int smbus_i2c_recv(i2c_slave *s)
return ret;
}
-static int smbus_i2c_send(i2c_slave *s, uint8_t data)
+static int smbus_i2c_send(I2CSlave *s, uint8_t data)
{
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, s);
+ SMBusDevice *dev = SMBUS_DEVICE(s);
switch (dev->mode) {
case SMBUS_WRITE_DATA:
@@ -198,22 +199,12 @@ static int smbus_i2c_send(i2c_slave *s, uint8_t data)
return 0;
}
-static int smbus_device_init(i2c_slave *i2c)
+static int smbus_device_init(I2CSlave *i2c)
{
- SMBusDeviceInfo *t = container_of(i2c->info, SMBusDeviceInfo, i2c);
- SMBusDevice *dev = FROM_I2C_SLAVE(SMBusDevice, i2c);
-
- return t->init(dev);
-}
+ SMBusDevice *dev = SMBUS_DEVICE(i2c);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev);
-void smbus_register_device(SMBusDeviceInfo *info)
-{
- assert(info->i2c.qdev.size >= sizeof(SMBusDevice));
- info->i2c.init = smbus_device_init;
- info->i2c.event = smbus_i2c_event;
- info->i2c.recv = smbus_i2c_recv;
- info->i2c.send = smbus_i2c_send;
- i2c_register_slave(&info->i2c);
+ return sc->init(dev);
}
/* Master device commands. */
@@ -316,3 +307,29 @@ void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *dat
i2c_send(bus, data[i]);
i2c_end_transfer(bus);
}
+
+static void smbus_device_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ sc->init = smbus_device_init;
+ sc->event = smbus_i2c_event;
+ sc->recv = smbus_i2c_recv;
+ sc->send = smbus_i2c_send;
+}
+
+static TypeInfo smbus_device_type_info = {
+ .name = TYPE_SMBUS_DEVICE,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(SMBusDevice),
+ .abstract = true,
+ .class_size = sizeof(SMBusDeviceClass),
+ .class_init = smbus_device_class_init,
+};
+
+static void smbus_device_register_devices(void)
+{
+ type_register_static(&smbus_device_type_info);
+}
+
+device_init(smbus_device_register_devices);
diff --git a/hw/smbus.h b/hw/smbus.h
index a39871593b..6ed45bd03d 100644
--- a/hw/smbus.h
+++ b/hw/smbus.h
@@ -1,3 +1,6 @@
+#ifndef QEMU_SMBUS_H
+#define QEMU_SMBUS_H
+
/*
* QEMU SMBus API
*
@@ -24,19 +27,17 @@
#include "i2c.h"
-struct SMBusDevice {
- /* The SMBus protocol is implemented on top of I2C. */
- i2c_slave i2c;
-
- /* Remaining fields for internal use only. */
- int mode;
- int data_len;
- uint8_t data_buf[34]; /* command + len + 32 bytes of data. */
- uint8_t command;
-};
+#define TYPE_SMBUS_DEVICE "smbus-device"
+#define SMBUS_DEVICE(obj) \
+ OBJECT_CHECK(SMBusDevice, (obj), TYPE_SMBUS_DEVICE)
+#define SMBUS_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SMBusDeviceClass, (klass), TYPE_SMBUS_DEVICE)
+#define SMBUS_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SMBusDeviceClass, (obj), TYPE_SMBUS_DEVICE)
-typedef struct {
- I2CSlaveInfo i2c;
+typedef struct SMBusDeviceClass
+{
+ I2CSlaveClass parent_class;
int (*init)(SMBusDevice *dev);
void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
void (*send_byte)(SMBusDevice *dev, uint8_t val);
@@ -51,9 +52,18 @@ typedef struct {
byte at a time. The device is responsible for adding the length
byte on block reads. */
uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n);
-} SMBusDeviceInfo;
+} SMBusDeviceClass;
-void smbus_register_device(SMBusDeviceInfo *info);
+struct SMBusDevice {
+ /* The SMBus protocol is implemented on top of I2C. */
+ I2CSlave i2c;
+
+ /* Remaining fields for internal use only. */
+ int mode;
+ int data_len;
+ uint8_t data_buf[34]; /* command + len + 32 bytes of data. */
+ uint8_t command;
+};
/* Master device commands. */
void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read);
@@ -69,3 +79,5 @@ void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *dat
void smbus_eeprom_init(i2c_bus *smbus, int nb_eeprom,
const uint8_t *eeprom_spd, int size);
+
+#endif
diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c
index 5d080abed7..9d96cbe41a 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -104,24 +104,35 @@ static int smbus_eeprom_initfn(SMBusDevice *dev)
return 0;
}
-static SMBusDeviceInfo smbus_eeprom_info = {
- .i2c.qdev.name = "smbus-eeprom",
- .i2c.qdev.size = sizeof(SMBusEEPROMDevice),
- .i2c.qdev.props = (Property[]) {
- DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
- DEFINE_PROP_END_OF_LIST(),
- },
- .init = smbus_eeprom_initfn,
- .quick_cmd = eeprom_quick_cmd,
- .send_byte = eeprom_send_byte,
- .receive_byte = eeprom_receive_byte,
- .write_data = eeprom_write_data,
- .read_data = eeprom_read_data
+static Property smbus_eeprom_properties[] = {
+ DEFINE_PROP_PTR("data", SMBusEEPROMDevice, data),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass);
+
+ sc->init = smbus_eeprom_initfn;
+ sc->quick_cmd = eeprom_quick_cmd;
+ sc->send_byte = eeprom_send_byte;
+ sc->receive_byte = eeprom_receive_byte;
+ sc->write_data = eeprom_write_data;
+ sc->read_data = eeprom_read_data;
+ dc->props = smbus_eeprom_properties;
+}
+
+static TypeInfo smbus_eeprom_info = {
+ .name = "smbus-eeprom",
+ .parent = TYPE_SMBUS_DEVICE,
+ .instance_size = sizeof(SMBusEEPROMDevice),
+ .class_init = smbus_eeprom_class_initfn,
};
static void smbus_eeprom_register_devices(void)
{
- smbus_register_device(&smbus_eeprom_info);
+ type_register_static(&smbus_eeprom_info);
}
device_init(smbus_eeprom_register_devices)
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 82b8811459..1bf2901d1a 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -752,27 +752,38 @@ static int smc91c111_init1(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_smc91c111_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
/* ??? Save/restore. */
return 0;
}
-static SysBusDeviceInfo smc91c111_info = {
- .init = smc91c111_init1,
- .qdev.name = "smc91c111",
- .qdev.size = sizeof(smc91c111_state),
- .qdev.vmsd = &vmstate_smc91c111,
- .qdev.reset = smc91c111_reset,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property smc91c111_properties[] = {
+ DEFINE_NIC_PROPERTIES(smc91c111_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void smc91c111_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = smc91c111_init1;
+ dc->reset = smc91c111_reset;
+ dc->vmsd = &vmstate_smc91c111;
+ dc->props = smc91c111_properties;
+}
+
+static TypeInfo smc91c111_info = {
+ .name = "smc91c111",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(smc91c111_state),
+ .class_init = smc91c111_class_init,
};
static void smc91c111_register_devices(void)
{
- sysbus_register_withprop(&smc91c111_info);
+ type_register_static(&smc91c111_info);
}
/* Legacy helper function. Should go away when machine config files are
diff --git a/hw/spapr.c b/hw/spapr.c
index 0e1f80dfdc..dffb6a2a50 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -50,19 +50,29 @@
#include <libfdt.h>
-#define KERNEL_LOAD_ADDR 0x00000000
-#define INITRD_LOAD_ADDR 0x02800000
+/* SLOF memory layout:
+ *
+ * SLOF raw image loaded at 0, copies its romfs right below the flat
+ * device-tree, then position SLOF itself 31M below that
+ *
+ * So we set FW_OVERHEAD to 40MB which should account for all of that
+ * and more
+ *
+ * We load our kernel at 4M, leaving space for SLOF initial image
+ */
#define FDT_MAX_SIZE 0x10000
#define RTAS_MAX_SIZE 0x10000
#define FW_MAX_SIZE 0x400000
#define FW_FILE_NAME "slof.bin"
+#define FW_OVERHEAD 0x2800000
+#define KERNEL_LOAD_ADDR FW_MAX_SIZE
-#define MIN_RMA_SLOF 128UL
+#define MIN_RMA_SLOF 128UL
#define TIMEBASE_FREQ 512000000ULL
#define MAX_CPUS 256
-#define XICS_IRQS 1024
+#define XICS_IRQS 1024
#define SPAPR_PCI_BUID 0x800000020000001ULL
#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000)
@@ -139,6 +149,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
target_phys_addr_t rma_size,
target_phys_addr_t initrd_base,
target_phys_addr_t initrd_size,
+ target_phys_addr_t kernel_size,
const char *boot_device,
const char *kernel_cmdline,
long hash_shift)
@@ -176,6 +187,12 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
fdt = g_malloc0(FDT_MAX_SIZE);
_FDT((fdt_create(fdt, FDT_MAX_SIZE)));
+ if (kernel_size) {
+ _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size)));
+ }
+ if (initrd_size) {
+ _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size)));
+ }
_FDT((fdt_finish_reservemap(fdt)));
/* Root node */
@@ -197,15 +214,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
&start_prop, sizeof(start_prop))));
_FDT((fdt_property(fdt, "linux,initrd-end",
&end_prop, sizeof(end_prop))));
- _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
+ if (kernel_size) {
+ uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
+ cpu_to_be64(kernel_size) };
- /*
- * Because we don't always invoke any firmware, we can't rely on
- * that to do BAR allocation. Long term, we should probably do
- * that ourselves, but for now, this setting (plus advertising the
- * current BARs as 0) causes sufficiently recent kernels to to the
- * BAR assignment themselves */
- _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0)));
+ _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
+ }
+ _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
_FDT((fdt_end_node(fdt)));
@@ -445,6 +460,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
_FDT((fdt_pack(fdt)));
+ if (fdt_totalsize(fdt) > FDT_MAX_SIZE) {
+ hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n",
+ fdt_totalsize(fdt), FDT_MAX_SIZE);
+ exit(1);
+ }
+
cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt));
g_free(fdt);
@@ -494,8 +515,9 @@ static void ppc_spapr_init(ram_addr_t ram_size,
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
target_phys_addr_t rma_alloc_size, rma_size;
- uint32_t initrd_base;
- long kernel_size, initrd_size, fw_size;
+ uint32_t initrd_base = 0;
+ long kernel_size = 0, initrd_size = 0;
+ long load_limit, rtas_limit, fw_size;
long pteg_shift = 17;
char *filename;
@@ -517,11 +539,13 @@ static void ppc_spapr_init(ram_addr_t ram_size,
rma_size = ram_size;
}
- /* We place the device tree just below either the top of the RMA,
+ /* We place the device tree and RTAS just below either the top of the RMA,
* or just below 2GB, whichever is lowere, so that it can be
* processed with 32-bit real mode code if necessary */
- spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE;
- spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE;
+ rtas_limit = MIN(rma_size, 0x80000000);
+ spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE;
+ spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE;
+ load_limit = spapr->fdt_addr - FW_OVERHEAD;
/* init CPUs */
if (cpu_model == NULL) {
@@ -577,13 +601,19 @@ static void ppc_spapr_init(ram_addr_t ram_size,
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr,
- ram_size - spapr->rtas_addr);
+ rtas_limit - spapr->rtas_addr);
if (spapr->rtas_size < 0) {
hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
exit(1);
}
+ if (spapr->rtas_size > RTAS_MAX_SIZE) {
+ hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n",
+ spapr->rtas_size, RTAS_MAX_SIZE);
+ exit(1);
+ }
g_free(filename);
+
/* Set up Interrupt Controller */
spapr->icp = xics_system_init(XICS_IRQS);
spapr->next_irq = 16;
@@ -622,6 +652,20 @@ static void ppc_spapr_init(ram_addr_t ram_size,
spapr_vscsi_create(spapr->vio_bus, 0x2000 + i);
}
+ if (rma_size < (MIN_RMA_SLOF << 20)) {
+ fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
+ "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
+ exit(1);
+ }
+
+ fprintf(stderr, "sPAPR memory map:\n");
+ fprintf(stderr, "RTAS : 0x%08lx..%08lx\n",
+ (unsigned long)spapr->rtas_addr,
+ (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1));
+ fprintf(stderr, "FDT : 0x%08lx..%08lx\n",
+ (unsigned long)spapr->fdt_addr,
+ (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1));
+
if (kernel_filename) {
uint64_t lowaddr = 0;
@@ -630,57 +674,60 @@ static void ppc_spapr_init(ram_addr_t ram_size,
if (kernel_size < 0) {
kernel_size = load_image_targphys(kernel_filename,
KERNEL_LOAD_ADDR,
- ram_size - KERNEL_LOAD_ADDR);
+ load_limit - KERNEL_LOAD_ADDR);
}
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
+ fprintf(stderr, "Kernel : 0x%08x..%08lx\n",
+ KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1);
/* load initrd */
if (initrd_filename) {
- initrd_base = INITRD_LOAD_ADDR;
+ /* Try to locate the initrd in the gap between the kernel
+ * and the firmware. Add a bit of space just in case
+ */
+ initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff;
initrd_size = load_image_targphys(initrd_filename, initrd_base,
- ram_size - initrd_base);
+ load_limit - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
+ fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n",
+ (long)initrd_base, (long)(initrd_base + initrd_size - 1));
} else {
initrd_base = 0;
initrd_size = 0;
}
+ }
- spapr->entry_point = KERNEL_LOAD_ADDR;
- } else {
- if (rma_size < (MIN_RMA_SLOF << 20)) {
- fprintf(stderr, "qemu: pSeries SLOF firmware requires >= "
- "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF);
- exit(1);
- }
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
- fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
- if (fw_size < 0) {
- hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
- exit(1);
- }
- g_free(filename);
- spapr->entry_point = 0x100;
- initrd_base = 0;
- initrd_size = 0;
-
- /* SLOF will startup the secondary CPUs using RTAS,
- rather than expecting a kexec() style entry */
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- env->halted = 1;
- }
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME);
+ fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE);
+ if (fw_size < 0) {
+ hw_error("qemu: could not load LPAR rtas '%s'\n", filename);
+ exit(1);
+ }
+ g_free(filename);
+ fprintf(stderr, "Firmware load : 0x%08x..%08lx\n",
+ 0, fw_size);
+ fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n",
+ load_limit, (unsigned long)spapr->fdt_addr);
+
+ spapr->entry_point = 0x100;
+
+ /* SLOF will startup the secondary CPUs using RTAS */
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ env->halted = 1;
}
/* Prepare the device tree */
spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size,
initrd_base, initrd_size,
+ kernel_size,
boot_device, kernel_cmdline,
pteg_shift + 7);
assert(spapr->fdt_skel != NULL);
@@ -693,7 +740,6 @@ static QEMUMachine spapr_machine = {
.desc = "pSeries Logical Partition (PAPR compliant)",
.init = ppc_spapr_init,
.max_cpus = MAX_CPUS,
- .no_vga = 1,
.no_parallel = 1,
.use_scsi = 1,
};
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
index 45674c4cb9..79b394132b 100644
--- a/hw/spapr_llan.c
+++ b/hw/spapr_llan.c
@@ -189,7 +189,7 @@ static int spapr_vlan_init(VIOsPAPRDevice *sdev)
qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
- sdev->qdev.info->name, sdev->qdev.id, dev);
+ object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
qemu_format_nic_info_str(&dev->nic->nc, dev->nicconf.macaddr.a);
return 0;
@@ -474,30 +474,41 @@ static target_ulong h_multicast_ctrl(CPUState *env, sPAPREnvironment *spapr,
return H_SUCCESS;
}
-static VIOsPAPRDeviceInfo spapr_vlan = {
- .init = spapr_vlan_init,
- .devnode = spapr_vlan_devnode,
- .dt_name = "l-lan",
- .dt_type = "network",
- .dt_compatible = "IBM,l-lan",
- .signal_mask = 0x1,
- .qdev.name = "spapr-vlan",
- .qdev.size = sizeof(VIOsPAPRVLANDevice),
- .qdev.props = (Property[]) {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000),
- DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spapr_vlan_properties[] = {
+ DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev, 0x1000, 0x10000000),
+ DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vlan_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+ k->init = spapr_vlan_init;
+ k->devnode = spapr_vlan_devnode;
+ k->dt_name = "l-lan";
+ k->dt_type = "network";
+ k->dt_compatible = "IBM,l-lan";
+ k->signal_mask = 0x1;
+ dc->props = spapr_vlan_properties;
+}
+
+static TypeInfo spapr_vlan_info = {
+ .name = "spapr-vlan",
+ .parent = TYPE_VIO_SPAPR_DEVICE,
+ .instance_size = sizeof(VIOsPAPRVLANDevice),
+ .class_init = spapr_vlan_class_init,
};
static void spapr_vlan_register(void)
{
- spapr_vio_bus_register_withprop(&spapr_vlan);
spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
h_add_logical_lan_buffer);
spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+ type_register_static(&spapr_vlan_info);
}
device_init(spapr_vlan_register);
diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c
index 9b6a032cce..ed2e4b33e7 100644
--- a/hw/spapr_pci.c
+++ b/hw/spapr_pci.c
@@ -62,6 +62,30 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr,
return NULL;
}
+static uint32_t rtas_pci_cfgaddr(uint32_t arg)
+{
+ return ((arg >> 20) & 0xf00) | (arg & 0xff);
+}
+
+static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
+ uint32_t limit, uint32_t len)
+{
+ if ((addr + len) <= limit) {
+ return pci_host_config_read_common(pci_dev, addr, limit, len);
+ } else {
+ return ~0x0;
+ }
+}
+
+static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr,
+ uint32_t limit, uint32_t val,
+ uint32_t len)
+{
+ if ((addr + len) <= limit) {
+ pci_host_config_write_common(pci_dev, addr, limit, val, len);
+ }
+}
+
static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
uint32_t token, uint32_t nargs,
target_ulong args,
@@ -76,8 +100,8 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr,
return;
}
size = rtas_ld(args, 3);
- addr = rtas_ld(args, 0) & 0xFF;
- val = pci_default_read_config(dev, addr, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
rtas_st(rets, 0, 0);
rtas_st(rets, 1, val);
}
@@ -95,8 +119,8 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr,
return;
}
size = rtas_ld(args, 1);
- addr = rtas_ld(args, 0) & 0xFF;
- val = pci_default_read_config(dev, addr, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size);
rtas_st(rets, 0, 0);
rtas_st(rets, 1, val);
}
@@ -116,8 +140,8 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr,
}
val = rtas_ld(args, 4);
size = rtas_ld(args, 3);
- addr = rtas_ld(args, 0) & 0xFF;
- pci_default_write_config(dev, addr, val, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
rtas_st(rets, 0, 0);
}
@@ -135,8 +159,8 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr,
}
val = rtas_ld(args, 2);
size = rtas_ld(args, 1);
- addr = rtas_ld(args, 0) & 0xFF;
- pci_default_write_config(dev, addr, val, size);
+ addr = rtas_pci_cfgaddr(rtas_ld(args, 0));
+ rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size);
rtas_st(rets, 0, 0);
}
@@ -190,17 +214,38 @@ static int spapr_main_pci_host_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo spapr_main_pci_host_info = {
- .qdev.name = "spapr-pci-host-bridge",
- .qdev.size = sizeof(PCIDevice),
- .init = spapr_main_pci_host_init,
+static void spapr_main_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = spapr_main_pci_host_init;
+}
+
+static TypeInfo spapr_main_pci_host_info = {
+ .name = "spapr-pci-host-bridge-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = spapr_main_pci_host_class_init,
+};
+
+static void spapr_phb_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = spapr_phb_init;
+}
+
+static TypeInfo spapr_phb_info = {
+ .name = "spapr-pci-host-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(sPAPRPHBState),
+ .class_init = spapr_phb_class_init,
};
static void spapr_register_devices(void)
{
- sysbus_register_dev("spapr-pci-host-bridge", sizeof(sPAPRPHBState),
- spapr_phb_init);
- pci_qdev_register(&spapr_main_pci_host_info);
+ type_register_static(&spapr_phb_info);
+ type_register_static(&spapr_main_pci_host_info);
}
device_init(spapr_register_devices)
@@ -319,31 +364,13 @@ void spapr_create_phb(sPAPREnvironment *spapr,
#define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
-static uint32_t regtype_to_ss(uint8_t type)
-{
- if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- return 3;
- }
- if (type == PCI_BASE_ADDRESS_SPACE_IO) {
- return 1;
- }
- return 2;
-}
-
int spapr_populate_pci_devices(sPAPRPHBState *phb,
uint32_t xics_phandle,
void *fdt)
{
PCIBus *bus = phb->host_state.bus;
- int bus_off, node_off = 0, devid, fn, i, n, devices;
- DeviceState *qdev;
+ int bus_off, i;
char nodename[256];
- struct {
- uint32_t hi;
- uint64_t addr;
- uint64_t size;
- } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
- assigned_addresses[PCI_NUM_REGIONS];
uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
struct {
uint32_t hi;
@@ -364,7 +391,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
};
uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 };
uint32_t interrupt_map_mask[] = {
- cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
+ cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0};
uint32_t interrupt_map[bus->nirq][7];
/* Start populating the FDT */
@@ -392,117 +419,26 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+ _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
+
+ /* Build the interrupt-map, this must matches what is done
+ * in pci_spapr_map_irq
+ */
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
&interrupt_map_mask, sizeof(interrupt_map_mask)));
-
- /* Populate PCI devices and allocate IRQs */
- devices = 0;
- QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
- PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- int irq_index = pci_spapr_map_irq(dev, 0);
- uint32_t *irqmap = interrupt_map[devices];
- uint8_t *config = dev->config;
-
- devid = dev->devfn >> 3;
- fn = dev->devfn & 7;
-
- sprintf(nodename, "pci@%u,%u", devid, fn);
-
- /* Allocate interrupt from the map */
- if (devid > bus->nirq) {
- printf("Unexpected behaviour in spapr_populate_pci_devices,"
- "wrong devid %u\n", devid);
- exit(-1);
- }
- irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+ for (i = 0; i < 7; i++) {
+ uint32_t *irqmap = interrupt_map[i];
+ irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0));
irqmap[1] = 0;
irqmap[2] = 0;
irqmap[3] = 0;
irqmap[4] = cpu_to_be32(xics_phandle);
- irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq);
+ irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq);
irqmap[6] = cpu_to_be32(0x8);
-
- /* Add node to FDT */
- node_off = fdt_add_subnode(fdt, bus_off, nodename);
- if (node_off < 0) {
- return node_off;
- }
-
- _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
- pci_get_word(&config[PCI_VENDOR_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
- pci_get_word(&config[PCI_DEVICE_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
- pci_get_byte(&config[PCI_REVISION_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
- pci_get_long(&config[PCI_CLASS_REVISION]) >> 8));
- _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
- pci_get_word(&config[PCI_SUBSYSTEM_ID])));
- _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
- pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID])));
-
- /* Config space region comes first */
- reg[0].hi = cpu_to_be32(
- b_n(0) |
- b_p(0) |
- b_t(0) |
- b_ss(0/*config*/) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn));
- reg[0].addr = 0;
- reg[0].size = 0;
-
- n = 0;
- for (i = 0; i < ARRAY_SIZE(bars); ++i) {
- if (0 == dev->io_regions[i].size) {
- continue;
- }
-
- reg[n+1].hi = cpu_to_be32(
- b_n(0) |
- b_p(0) |
- b_t(0) |
- b_ss(regtype_to_ss(dev->io_regions[i].type)) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn) |
- b_rrrrrrrr(bars[i]));
- reg[n+1].addr = 0;
- reg[n+1].size = cpu_to_be64(dev->io_regions[i].size);
-
- assigned_addresses[n].hi = cpu_to_be32(
- b_n(1) |
- b_p(0) |
- b_t(0) |
- b_ss(regtype_to_ss(dev->io_regions[i].type)) |
- b_bbbbbbbb(0) |
- b_ddddd(devid) |
- b_fff(fn) |
- b_rrrrrrrr(bars[i]));
-
- /*
- * Writing zeroes to assigned_addresses causes the guest kernel to
- * reassign BARs
- */
- assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr);
- assigned_addresses[n].size = reg[n+1].size;
-
- ++n;
- }
- _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
- _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
- assigned_addresses,
- sizeof(assigned_addresses[0])*(n)));
- _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
- pci_get_byte(&config[PCI_INTERRUPT_PIN])));
-
- ++devices;
}
-
/* Write interrupt map */
_FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
- devices * sizeof(interrupt_map[0])));
+ 7 * sizeof(interrupt_map[0])));
return 0;
}
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 7a86dc8d2c..64f0009814 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -75,11 +75,11 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
static char *vio_format_dev_name(VIOsPAPRDevice *dev)
{
- VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
char *name;
/* Device tree style name device@reg */
- if (asprintf(&name, "%s@%x", info->dt_name, dev->reg) < 0) {
+ if (asprintf(&name, "%s@%x", pc->dt_name, dev->reg) < 0) {
return NULL;
}
@@ -90,7 +90,7 @@ static char *vio_format_dev_name(VIOsPAPRDevice *dev)
static int vio_make_devnode(VIOsPAPRDevice *dev,
void *fdt)
{
- VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
int vdevice_off, node_off, ret;
char *dt_name;
@@ -115,17 +115,17 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
return ret;
}
- if (info->dt_type) {
+ if (pc->dt_type) {
ret = fdt_setprop_string(fdt, node_off, "device_type",
- info->dt_type);
+ pc->dt_type);
if (ret < 0) {
return ret;
}
}
- if (info->dt_compatible) {
+ if (pc->dt_compatible) {
ret = fdt_setprop_string(fdt, node_off, "compatible",
- info->dt_compatible);
+ pc->dt_compatible);
if (ret < 0) {
return ret;
}
@@ -163,8 +163,8 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
}
- if (info->devnode) {
- ret = (info->devnode)(dev, fdt, node_off);
+ if (pc->devnode) {
+ ret = (pc->devnode)(dev, fdt, node_off);
if (ret < 0) {
return ret;
}
@@ -621,7 +621,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
rtas_st(rets, 0, 0);
}
-static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
+static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
{
VIOsPAPRDevice *other_sdev;
DeviceState *qdev;
@@ -639,7 +639,9 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
if (other_sdev != sdev && other_sdev->reg == sdev->reg) {
fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
- info->qdev.name, other_sdev->qdev.info->name, sdev->reg);
+ object_get_typename(OBJECT(sdev)),
+ object_get_typename(OBJECT(qdev)),
+ sdev->reg);
return -EEXIST;
}
}
@@ -647,14 +649,14 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
return 0;
}
-static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
+static int spapr_vio_busdev_init(DeviceState *qdev)
{
- VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
+ VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
char *id;
int ret;
- ret = spapr_vio_check_reg(dev, info);
+ ret = spapr_vio_check_reg(dev);
if (ret) {
return ret;
}
@@ -675,16 +677,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
rtce_init(dev);
- return info->init(dev);
-}
-
-void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
-{
- info->qdev.init = spapr_vio_busdev_init;
- info->qdev.bus_info = &spapr_vio_bus_info;
-
- assert(info->qdev.size >= sizeof(VIOsPAPRDevice));
- qdev_register(&info->qdev);
+ return pc->init(dev);
}
static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
@@ -694,15 +687,15 @@ static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
target_ulong reg = args[0];
target_ulong mode = args[1];
VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
- VIOsPAPRDeviceInfo *info;
+ VIOsPAPRDeviceClass *pc;
if (!dev) {
return H_PARAMETER;
}
- info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+ pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
- if (mode & ~info->signal_mask) {
+ if (mode & ~pc->signal_mask) {
return H_PARAMETER;
}
@@ -753,16 +746,42 @@ static int spapr_vio_bridge_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo spapr_vio_bridge_info = {
- .init = spapr_vio_bridge_init,
- .qdev.name = "spapr-vio-bridge",
- .qdev.size = sizeof(SysBusDevice),
- .qdev.no_user = 1,
+static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = spapr_vio_bridge_init;
+ dc->no_user = 1;
+}
+
+static TypeInfo spapr_vio_bridge_info = {
+ .name = "spapr-vio-bridge",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = spapr_vio_bridge_class_init,
+};
+
+static void vio_spapr_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = spapr_vio_busdev_init;
+ k->bus_info = &spapr_vio_bus_info;
+}
+
+static TypeInfo spapr_vio_type_info = {
+ .name = TYPE_VIO_SPAPR_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VIOsPAPRDevice),
+ .abstract = true,
+ .class_size = sizeof(VIOsPAPRDeviceClass),
+ .class_init = vio_spapr_device_class_init,
};
static void spapr_vio_register_devices(void)
{
- sysbus_register_withprop(&spapr_vio_bridge_info);
+ type_register_static(&spapr_vio_bridge_info);
+ type_register_static(&spapr_vio_type_info);
}
device_init(spapr_vio_register_devices)
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 0984d559db..d8527bed90 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -34,6 +34,14 @@ enum VIOsPAPR_TCEAccess {
#define SPAPR_VTY_BASE_ADDRESS 0x30000000
+#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device"
+#define VIO_SPAPR_DEVICE(obj) \
+ OBJECT_CHECK(VIOsPAPRDevice, (obj), TYPE_VIO_SPAPR_DEVICE)
+#define VIO_SPAPR_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VIOsPAPRDeviceClass, (klass), TYPE_VIO_SPAPR_DEVICE)
+#define VIO_SPAPR_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VIOsPAPRDeviceClass, (obj), TYPE_VIO_SPAPR_DEVICE)
+
struct VIOsPAPRDevice;
typedef struct VIOsPAPR_RTCE {
@@ -47,7 +55,20 @@ typedef struct VIOsPAPR_CRQ {
int(*SendFunc)(struct VIOsPAPRDevice *vdev, uint8_t *crq);
} VIOsPAPR_CRQ;
-typedef struct VIOsPAPRDevice {
+typedef struct VIOsPAPRDevice VIOsPAPRDevice;
+typedef struct VIOsPAPRBus VIOsPAPRBus;
+
+typedef struct VIOsPAPRDeviceClass {
+ DeviceClass parent_class;
+
+ const char *dt_name, *dt_type, *dt_compatible;
+ target_ulong signal_mask;
+ int (*init)(VIOsPAPRDevice *dev);
+ void (*hcalls)(VIOsPAPRBus *bus);
+ int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
+} VIOsPAPRDeviceClass;
+
+struct VIOsPAPRDevice {
DeviceState qdev;
uint32_t reg;
uint32_t flags;
@@ -59,28 +80,23 @@ typedef struct VIOsPAPRDevice {
VIOsPAPR_RTCE *rtce_table;
int kvmtce_fd;
VIOsPAPR_CRQ crq;
-} VIOsPAPRDevice;
+};
#define DEFINE_SPAPR_PROPERTIES(type, field, default_reg, default_dma_window) \
DEFINE_PROP_UINT32("reg", type, field.reg, default_reg), \
DEFINE_PROP_UINT32("dma-window", type, field.rtce_window_size, \
default_dma_window)
-typedef struct VIOsPAPRBus {
+struct VIOsPAPRBus {
BusState bus;
-} VIOsPAPRBus;
-
-typedef struct {
- DeviceInfo qdev;
const char *dt_name, *dt_type, *dt_compatible;
target_ulong signal_mask;
int (*init)(VIOsPAPRDevice *dev);
int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
-} VIOsPAPRDeviceInfo;
+};
extern VIOsPAPRBus *spapr_vio_bus_init(void);
extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
-extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
extern int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 00e2d2d5d3..9cfce19a73 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -947,23 +947,34 @@ static int spapr_vscsi_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
return 0;
}
-static VIOsPAPRDeviceInfo spapr_vscsi = {
- .init = spapr_vscsi_init,
- .devnode = spapr_vscsi_devnode,
- .dt_name = "v-scsi",
- .dt_type = "vscsi",
- .dt_compatible = "IBM,v-scsi",
- .signal_mask = 0x00000001,
- .qdev.name = "spapr-vscsi",
- .qdev.size = sizeof(VSCSIState),
- .qdev.props = (Property[]) {
- DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spapr_vscsi_properties[] = {
+ DEFINE_SPAPR_PROPERTIES(VSCSIState, vdev, 0x2000, 0x10000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+ k->init = spapr_vscsi_init;
+ k->devnode = spapr_vscsi_devnode;
+ k->dt_name = "v-scsi";
+ k->dt_type = "vscsi";
+ k->dt_compatible = "IBM,v-scsi";
+ k->signal_mask = 0x00000001;
+ dc->props = spapr_vscsi_properties;
+}
+
+static TypeInfo spapr_vscsi_info = {
+ .name = "spapr-vscsi",
+ .parent = TYPE_VIO_SPAPR_DEVICE,
+ .instance_size = sizeof(VSCSIState),
+ .class_init = spapr_vscsi_class_init,
};
static void spapr_vscsi_register(void)
{
- spapr_vio_bus_register_withprop(&spapr_vscsi);
+ type_register_static(&spapr_vscsi_info);
}
device_init(spapr_vscsi_register);
diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c
index c5fb0968ed..a954e7d29b 100644
--- a/hw/spapr_vty.c
+++ b/hw/spapr_vty.c
@@ -135,18 +135,29 @@ void spapr_vty_create(VIOsPAPRBus *bus, uint32_t reg, CharDriverState *chardev)
qdev_init_nofail(dev);
}
-static VIOsPAPRDeviceInfo spapr_vty = {
- .init = spapr_vty_init,
- .dt_name = "vty",
- .dt_type = "serial",
- .dt_compatible = "hvterm1",
- .qdev.name = "spapr-vty",
- .qdev.size = sizeof(VIOsPAPRVTYDevice),
- .qdev.props = (Property[]) {
- DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
- DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spapr_vty_properties[] = {
+ DEFINE_SPAPR_PROPERTIES(VIOsPAPRVTYDevice, sdev, SPAPR_VTY_BASE_ADDRESS, 0),
+ DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vty_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+ k->init = spapr_vty_init;
+ k->dt_name = "vty";
+ k->dt_type = "serial";
+ k->dt_compatible = "hvterm1";
+ dc->props = spapr_vty_properties;
+}
+
+static TypeInfo spapr_vty_info = {
+ .name = "spapr-vty",
+ .parent = TYPE_VIO_SPAPR_DEVICE,
+ .instance_size = sizeof(VIOsPAPRVTYDevice),
+ .class_init = spapr_vty_class_init,
};
VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
@@ -163,7 +174,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
selected = NULL;
QTAILQ_FOREACH(iter, &bus->bus.children, sibling) {
/* Only look at VTY devices */
- if (iter->info != &spapr_vty.qdev) {
+ if (!object_dynamic_cast(OBJECT(iter), "spapr-vty")) {
continue;
}
@@ -203,8 +214,8 @@ static VIOsPAPRDevice *vty_lookup(sPAPREnvironment *spapr, target_ulong reg)
static void spapr_vty_register(void)
{
- spapr_vio_bus_register_withprop(&spapr_vty);
spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+ type_register_static(&spapr_vty_info);
}
device_init(spapr_vty_register);
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index 035d2e205b..f07cc6fdf0 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -283,22 +283,33 @@ static int sparc32_dma_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo sparc32_dma_info = {
- .init = sparc32_dma_init1,
- .qdev.name = "sparc32_dma",
- .qdev.size = sizeof(DMAState),
- .qdev.vmsd = &vmstate_dma,
- .qdev.reset = dma_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
- DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property sparc32_dma_properties[] = {
+ DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu),
+ DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sparc32_dma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sparc32_dma_init1;
+ dc->reset = dma_reset;
+ dc->vmsd = &vmstate_dma;
+ dc->props = sparc32_dma_properties;
+}
+
+static TypeInfo sparc32_dma_info = {
+ .name = "sparc32_dma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(DMAState),
+ .class_init = sparc32_dma_class_init,
};
static void sparc32_dma_register_devices(void)
{
- sysbus_register_withprop(&sparc32_dma_info);
+ type_register_static(&sparc32_dma_info);
}
device_init(sparc32_dma_register_devices)
diff --git a/hw/spitz.c b/hw/spitz.c
index 9d129c22b9..4e6540d976 100644
--- a/hw/spitz.c
+++ b/hw/spitz.c
@@ -717,7 +717,7 @@ static void spitz_microdrive_attach(PXA2xxState *cpu, int slot)
static void spitz_wm8750_addr(void *opaque, int line, int level)
{
- i2c_slave *wm = (i2c_slave *) opaque;
+ I2CSlave *wm = (I2CSlave *) opaque;
if (level)
i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
else
@@ -1023,16 +1023,27 @@ static VMStateDescription vmstate_sl_nand_info = {
},
};
-static SysBusDeviceInfo sl_nand_info = {
- .init = sl_nand_init,
- .qdev.name = "sl-nand",
- .qdev.size = sizeof(SLNANDState),
- .qdev.vmsd = &vmstate_sl_nand_info,
- .qdev.props = (Property []) {
- DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
- DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property sl_nand_properties[] = {
+ DEFINE_PROP_UINT8("manf_id", SLNANDState, manf_id, NAND_MFR_SAMSUNG),
+ DEFINE_PROP_UINT8("chip_id", SLNANDState, chip_id, 0xf1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sl_nand_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sl_nand_init;
+ dc->vmsd = &vmstate_sl_nand_info;
+ dc->props = sl_nand_properties;
+}
+
+static TypeInfo sl_nand_info = {
+ .name = "sl-nand",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SLNANDState),
+ .class_init = sl_nand_class_init,
};
static VMStateDescription vmstate_spitz_kbd = {
@@ -1049,14 +1060,25 @@ static VMStateDescription vmstate_spitz_kbd = {
},
};
-static SysBusDeviceInfo spitz_keyboard_info = {
- .init = spitz_keyboard_init,
- .qdev.name = "spitz-keyboard",
- .qdev.size = sizeof(SpitzKeyboardState),
- .qdev.vmsd = &vmstate_spitz_kbd,
- .qdev.props = (Property []) {
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property spitz_keyboard_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spitz_keyboard_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = spitz_keyboard_init;
+ dc->vmsd = &vmstate_spitz_kbd;
+ dc->props = spitz_keyboard_properties;
+}
+
+static TypeInfo spitz_keyboard_info = {
+ .name = "spitz-keyboard",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SpitzKeyboardState),
+ .class_init = spitz_keyboard_class_init,
};
static const VMStateDescription vmstate_corgi_ssp_regs = {
@@ -1070,12 +1092,21 @@ static const VMStateDescription vmstate_corgi_ssp_regs = {
}
};
-static SSISlaveInfo corgi_ssp_info = {
- .qdev.name = "corgi-ssp",
- .qdev.size = sizeof(CorgiSSPState),
- .qdev.vmsd = &vmstate_corgi_ssp_regs,
- .init = corgi_ssp_init,
- .transfer = corgi_ssp_transfer
+static void corgi_ssp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = corgi_ssp_init;
+ k->transfer = corgi_ssp_transfer;
+ dc->vmsd = &vmstate_corgi_ssp_regs;
+}
+
+static TypeInfo corgi_ssp_info = {
+ .name = "corgi-ssp",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(CorgiSSPState),
+ .class_init = corgi_ssp_class_init,
};
static const VMStateDescription vmstate_spitz_lcdtg_regs = {
@@ -1090,20 +1121,29 @@ static const VMStateDescription vmstate_spitz_lcdtg_regs = {
}
};
-static SSISlaveInfo spitz_lcdtg_info = {
- .qdev.name = "spitz-lcdtg",
- .qdev.size = sizeof(SpitzLCDTG),
- .qdev.vmsd = &vmstate_spitz_lcdtg_regs,
- .init = spitz_lcdtg_init,
- .transfer = spitz_lcdtg_transfer
+static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = spitz_lcdtg_init;
+ k->transfer = spitz_lcdtg_transfer;
+ dc->vmsd = &vmstate_spitz_lcdtg_regs;
+}
+
+static TypeInfo spitz_lcdtg_info = {
+ .name = "spitz-lcdtg",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(SpitzLCDTG),
+ .class_init = spitz_lcdtg_class_init,
};
static void spitz_register_devices(void)
{
- ssi_register_slave(&corgi_ssp_info);
- ssi_register_slave(&spitz_lcdtg_info);
- sysbus_register_withprop(&spitz_keyboard_info);
- sysbus_register_withprop(&sl_nand_info);
+ type_register_static(&corgi_ssp_info);
+ type_register_static(&spitz_lcdtg_info);
+ type_register_static(&spitz_keyboard_info);
+ type_register_static(&sl_nand_info);
}
device_init(spitz_register_devices)
diff --git a/hw/ssd0303.c b/hw/ssd0303.c
index bcad7bf922..685602a584 100644
--- a/hw/ssd0303.c
+++ b/hw/ssd0303.c
@@ -42,7 +42,7 @@ enum ssd0303_cmd {
};
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
DisplayState *ds;
int row;
int col;
@@ -57,13 +57,13 @@ typedef struct {
uint8_t framebuffer[132*8];
} ssd0303_state;
-static int ssd0303_recv(i2c_slave *i2c)
+static int ssd0303_recv(I2CSlave *i2c)
{
BADF("Reads not implemented\n");
return -1;
}
-static int ssd0303_send(i2c_slave *i2c, uint8_t data)
+static int ssd0303_send(I2CSlave *i2c, uint8_t data)
{
ssd0303_state *s = (ssd0303_state *)i2c;
enum ssd0303_cmd old_cmd_state;
@@ -173,7 +173,7 @@ static int ssd0303_send(i2c_slave *i2c, uint8_t data)
return 0;
}
-static void ssd0303_event(i2c_slave *i2c, enum i2c_event event)
+static void ssd0303_event(I2CSlave *i2c, enum i2c_event event)
{
ssd0303_state *s = (ssd0303_state *)i2c;
switch (event) {
@@ -283,7 +283,7 @@ static const VMStateDescription vmstate_ssd0303 = {
}
};
-static int ssd0303_init(i2c_slave *i2c)
+static int ssd0303_init(I2CSlave *i2c)
{
ssd0303_state *s = FROM_I2C_SLAVE(ssd0303_state, i2c);
@@ -294,19 +294,28 @@ static int ssd0303_init(i2c_slave *i2c)
return 0;
}
-static I2CSlaveInfo ssd0303_info = {
- .qdev.name = "ssd0303",
- .qdev.size = sizeof(ssd0303_state),
- .qdev.vmsd = &vmstate_ssd0303,
- .init = ssd0303_init,
- .event = ssd0303_event,
- .recv = ssd0303_recv,
- .send = ssd0303_send
+static void ssd0303_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = ssd0303_init;
+ k->event = ssd0303_event;
+ k->recv = ssd0303_recv;
+ k->send = ssd0303_send;
+ dc->vmsd = &vmstate_ssd0303;
+}
+
+static TypeInfo ssd0303_info = {
+ .name = "ssd0303",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(ssd0303_state),
+ .class_init = ssd0303_class_init,
};
static void ssd0303_register_devices(void)
{
- i2c_register_slave(&ssd0303_info);
+ type_register_static(&ssd0303_info);
}
device_init(ssd0303_register_devices)
diff --git a/hw/ssd0323.c b/hw/ssd0323.c
index 1eb3823fed..3c43738ae1 100644
--- a/hw/ssd0323.c
+++ b/hw/ssd0323.c
@@ -340,16 +340,24 @@ static int ssd0323_init(SSISlave *dev)
return 0;
}
-static SSISlaveInfo ssd0323_info = {
- .qdev.name = "ssd0323",
- .qdev.size = sizeof(ssd0323_state),
- .init = ssd0323_init,
- .transfer = ssd0323_transfer
+static void ssd0323_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = ssd0323_init;
+ k->transfer = ssd0323_transfer;
+}
+
+static TypeInfo ssd0323_info = {
+ .name = "ssd0323",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ssd0323_state),
+ .class_init = ssd0323_class_init,
};
static void ssd03232_register_devices(void)
{
- ssi_register_slave(&ssd0323_info);
+ type_register_static(&ssd0323_info);
}
device_init(ssd03232_register_devices)
diff --git a/hw/ssi-sd.c b/hw/ssi-sd.c
index 2d89cfe522..f2e6cecb71 100644
--- a/hw/ssi-sd.c
+++ b/hw/ssi-sd.c
@@ -244,16 +244,24 @@ static int ssi_sd_init(SSISlave *dev)
return 0;
}
-static SSISlaveInfo ssi_sd_info = {
- .qdev.name = "ssi-sd",
- .qdev.size = sizeof(ssi_sd_state),
- .init = ssi_sd_init,
- .transfer = ssi_sd_transfer
+static void ssi_sd_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = ssi_sd_init;
+ k->transfer = ssi_sd_transfer;
+}
+
+static TypeInfo ssi_sd_info = {
+ .name = "ssi-sd",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ssi_sd_state),
+ .class_init = ssi_sd_class_init,
};
static void ssi_sd_register_devices(void)
{
- ssi_register_slave(&ssi_sd_info);
+ type_register_static(&ssi_sd_info);
}
device_init(ssi_sd_register_devices)
diff --git a/hw/ssi.c b/hw/ssi.c
index b47953a989..ead446c49a 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -21,10 +21,10 @@ static struct BusInfo ssi_bus_info = {
.size = sizeof(SSIBus),
};
-static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
+static int ssi_slave_init(DeviceState *dev)
{
- SSISlaveInfo *info = container_of(base_info, SSISlaveInfo, qdev);
- SSISlave *s = SSI_SLAVE_FROM_QDEV(dev);
+ SSISlave *s = SSI_SLAVE(dev);
+ SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
SSIBus *bus;
bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
@@ -33,18 +33,24 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
hw_error("Too many devices on SSI bus");
}
- s->info = info;
- return info->init(s);
+ return ssc->init(s);
}
-void ssi_register_slave(SSISlaveInfo *info)
+static void ssi_slave_class_init(ObjectClass *klass, void *data)
{
- assert(info->qdev.size >= sizeof(SSISlave));
- info->qdev.init = ssi_slave_init;
- info->qdev.bus_info = &ssi_bus_info;
- qdev_register(&info->qdev);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->init = ssi_slave_init;
+ dc->bus_info = &ssi_bus_info;
}
+static TypeInfo ssi_slave_info = {
+ .name = TYPE_SSI_SLAVE,
+ .parent = TYPE_DEVICE,
+ .class_init = ssi_slave_class_init,
+ .class_size = sizeof(SSISlaveClass),
+ .abstract = true,
+};
+
DeviceState *ssi_create_slave(SSIBus *bus, const char *name)
{
DeviceState *dev;
@@ -64,10 +70,19 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
{
DeviceState *dev;
SSISlave *slave;
+ SSISlaveClass *ssc;
dev = QTAILQ_FIRST(&bus->qbus.children);
if (!dev) {
return 0;
}
- slave = SSI_SLAVE_FROM_QDEV(dev);
- return slave->info->transfer(slave, val);
+ slave = SSI_SLAVE(dev);
+ ssc = SSI_SLAVE_GET_CLASS(slave);
+ return ssc->transfer(slave, val);
+}
+
+static void register_ssi_slave(void)
+{
+ type_register_static(&ssi_slave_info);
}
+
+device_init(register_ssi_slave);
diff --git a/hw/ssi.h b/hw/ssi.h
index 24610a80cb..06657d7c16 100644
--- a/hw/ssi.h
+++ b/hw/ssi.h
@@ -15,23 +15,29 @@
typedef struct SSISlave SSISlave;
+#define TYPE_SSI_SLAVE "ssi-slave"
+#define SSI_SLAVE(obj) \
+ OBJECT_CHECK(SSISlave, (obj), TYPE_SSI_SLAVE)
+#define SSI_SLAVE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SSISlaveClass, (klass), TYPE_SSI_SLAVE)
+#define SSI_SLAVE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SSISlaveClass, (obj), TYPE_SSI_SLAVE)
+
/* Slave devices. */
-typedef struct {
- DeviceInfo qdev;
+typedef struct SSISlaveClass {
+ DeviceClass parent_class;
+
int (*init)(SSISlave *dev);
uint32_t (*transfer)(SSISlave *dev, uint32_t val);
-} SSISlaveInfo;
+} SSISlaveClass;
struct SSISlave {
DeviceState qdev;
- SSISlaveInfo *info;
};
#define SSI_SLAVE_FROM_QDEV(dev) DO_UPCAST(SSISlave, qdev, dev)
#define FROM_SSI_SLAVE(type, dev) DO_UPCAST(type, ssidev, dev)
-void ssi_register_slave(SSISlaveInfo *info);
-
DeviceState *ssi_create_slave(SSIBus *bus, const char *name);
/* Master interface. */
diff --git a/hw/stellaris.c b/hw/stellaris.c
index 7a73074982..31a65cfb77 100644
--- a/hw/stellaris.c
+++ b/hw/stellaris.c
@@ -1394,22 +1394,69 @@ static void stellaris_machine_init(void)
machine_init(stellaris_machine_init);
-static SSISlaveInfo stellaris_ssi_bus_info = {
- .qdev.name = "evb6965-ssi",
- .qdev.size = sizeof(stellaris_ssi_bus_state),
- .init = stellaris_ssi_bus_init,
- .transfer = stellaris_ssi_bus_transfer
+static void stellaris_ssi_bus_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = stellaris_ssi_bus_init;
+ k->transfer = stellaris_ssi_bus_transfer;
+}
+
+static TypeInfo stellaris_ssi_bus_info = {
+ .name = "evb6965-ssi",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(stellaris_ssi_bus_state),
+ .class_init = stellaris_ssi_bus_class_init,
+};
+
+static void stellaris_i2c_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = stellaris_i2c_init;
+}
+
+static TypeInfo stellaris_i2c_info = {
+ .name = "stellaris-i2c",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(stellaris_i2c_state),
+ .class_init = stellaris_i2c_class_init,
+};
+
+static void stellaris_gptm_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = stellaris_gptm_init;
+}
+
+static TypeInfo stellaris_gptm_info = {
+ .name = "stellaris-gptm",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(gptm_state),
+ .class_init = stellaris_gptm_class_init,
+};
+
+static void stellaris_adc_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = stellaris_adc_init;
+}
+
+static TypeInfo stellaris_adc_info = {
+ .name = "stellaris-adc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(stellaris_adc_state),
+ .class_init = stellaris_adc_class_init,
};
static void stellaris_register_devices(void)
{
- sysbus_register_dev("stellaris-i2c", sizeof(stellaris_i2c_state),
- stellaris_i2c_init);
- sysbus_register_dev("stellaris-gptm", sizeof(gptm_state),
- stellaris_gptm_init);
- sysbus_register_dev("stellaris-adc", sizeof(stellaris_adc_state),
- stellaris_adc_init);
- ssi_register_slave(&stellaris_ssi_bus_info);
+ type_register_static(&stellaris_i2c_info);
+ type_register_static(&stellaris_gptm_info);
+ type_register_static(&stellaris_adc_info);
+ type_register_static(&stellaris_ssi_bus_info);
}
device_init(stellaris_register_devices)
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
index 866c9a2381..9b1be8dadc 100644
--- a/hw/stellaris_enet.c
+++ b/hw/stellaris_enet.c
@@ -411,7 +411,7 @@ static int stellaris_enet_init(SysBusDevice *dev)
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
stellaris_enet_reset(s);
@@ -420,19 +420,30 @@ static int stellaris_enet_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo stellaris_enet_info = {
- .init = stellaris_enet_init,
- .qdev.name = "stellaris_enet",
- .qdev.size = sizeof(stellaris_enet_state),
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property stellaris_enet_properties[] = {
+ DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stellaris_enet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = stellaris_enet_init;
+ dc->props = stellaris_enet_properties;
+}
+
+static TypeInfo stellaris_enet_info = {
+ .name = "stellaris_enet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(stellaris_enet_state),
+ .class_init = stellaris_enet_class_init,
};
static void stellaris_enet_register_devices(void)
{
- sysbus_register_withprop(&stellaris_enet_info);
+ type_register_static(&stellaris_enet_info);
}
device_init(stellaris_enet_register_devices)
diff --git a/hw/strongarm.c b/hw/strongarm.c
index fe63fd7ab7..8d2e7eb6fe 100644
--- a/hw/strongarm.c
+++ b/hw/strongarm.c
@@ -201,12 +201,21 @@ static VMStateDescription vmstate_strongarm_pic_regs = {
},
};
-static SysBusDeviceInfo strongarm_pic_info = {
- .init = strongarm_pic_initfn,
- .qdev.name = "strongarm_pic",
- .qdev.desc = "StrongARM PIC",
- .qdev.size = sizeof(StrongARMPICState),
- .qdev.vmsd = &vmstate_strongarm_pic_regs,
+static void strongarm_pic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_pic_initfn;
+ dc->desc = "StrongARM PIC";
+ dc->vmsd = &vmstate_strongarm_pic_regs;
+}
+
+static TypeInfo strongarm_pic_info = {
+ .name = "strongarm_pic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMPICState),
+ .class_init = strongarm_pic_class_init,
};
/* Real-Time Clock */
@@ -413,12 +422,21 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = {
},
};
-static SysBusDeviceInfo strongarm_rtc_sysbus_info = {
- .init = strongarm_rtc_init,
- .qdev.name = "strongarm-rtc",
- .qdev.desc = "StrongARM RTC Controller",
- .qdev.size = sizeof(StrongARMRTCState),
- .qdev.vmsd = &vmstate_strongarm_rtc_regs,
+static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_rtc_init;
+ dc->desc = "StrongARM RTC Controller";
+ dc->vmsd = &vmstate_strongarm_rtc_regs;
+}
+
+static TypeInfo strongarm_rtc_sysbus_info = {
+ .name = "strongarm-rtc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMRTCState),
+ .class_init = strongarm_rtc_sysbus_class_init,
};
/* GPIO */
@@ -646,11 +664,20 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = {
},
};
-static SysBusDeviceInfo strongarm_gpio_info = {
- .init = strongarm_gpio_initfn,
- .qdev.name = "strongarm-gpio",
- .qdev.desc = "StrongARM GPIO controller",
- .qdev.size = sizeof(StrongARMGPIOInfo),
+static void strongarm_gpio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_gpio_initfn;
+ dc->desc = "StrongARM GPIO controller";
+}
+
+static TypeInfo strongarm_gpio_info = {
+ .name = "strongarm-gpio",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMGPIOInfo),
+ .class_init = strongarm_gpio_class_init,
};
/* Peripheral Pin Controller */
@@ -803,11 +830,20 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = {
},
};
-static SysBusDeviceInfo strongarm_ppc_info = {
- .init = strongarm_ppc_init,
- .qdev.name = "strongarm-ppc",
- .qdev.desc = "StrongARM PPC controller",
- .qdev.size = sizeof(StrongARMPPCInfo),
+static void strongarm_ppc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_ppc_init;
+ dc->desc = "StrongARM PPC controller";
+}
+
+static TypeInfo strongarm_ppc_info = {
+ .name = "strongarm-ppc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMPPCInfo),
+ .class_init = strongarm_ppc_class_init,
};
/* UART Ports */
@@ -1245,17 +1281,28 @@ static const VMStateDescription vmstate_strongarm_uart_regs = {
},
};
-static SysBusDeviceInfo strongarm_uart_info = {
- .init = strongarm_uart_init,
- .qdev.name = "strongarm-uart",
- .qdev.desc = "StrongARM UART controller",
- .qdev.size = sizeof(StrongARMUARTState),
- .qdev.reset = strongarm_uart_reset,
- .qdev.vmsd = &vmstate_strongarm_uart_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property strongarm_uart_properties[] = {
+ DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void strongarm_uart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_uart_init;
+ dc->desc = "StrongARM UART controller";
+ dc->reset = strongarm_uart_reset;
+ dc->vmsd = &vmstate_strongarm_uart_regs;
+ dc->props = strongarm_uart_properties;
+}
+
+static TypeInfo strongarm_uart_info = {
+ .name = "strongarm-uart",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMUARTState),
+ .class_init = strongarm_uart_class_init,
};
/* Synchronous Serial Ports */
@@ -1479,13 +1526,22 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = {
},
};
-static SysBusDeviceInfo strongarm_ssp_info = {
- .init = strongarm_ssp_init,
- .qdev.name = "strongarm-ssp",
- .qdev.desc = "StrongARM SSP controller",
- .qdev.size = sizeof(StrongARMSSPState),
- .qdev.reset = strongarm_ssp_reset,
- .qdev.vmsd = &vmstate_strongarm_ssp_regs,
+static void strongarm_ssp_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = strongarm_ssp_init;
+ dc->desc = "StrongARM SSP controller";
+ dc->reset = strongarm_ssp_reset;
+ dc->vmsd = &vmstate_strongarm_ssp_regs;
+}
+
+static TypeInfo strongarm_ssp_info = {
+ .name = "strongarm-ssp",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(StrongARMSSPState),
+ .class_init = strongarm_ssp_class_init,
};
/* Main CPU functions */
@@ -1555,11 +1611,11 @@ StrongARMState *sa1110_init(MemoryRegion *sysmem,
static void strongarm_register_devices(void)
{
- sysbus_register_withprop(&strongarm_pic_info);
- sysbus_register_withprop(&strongarm_rtc_sysbus_info);
- sysbus_register_withprop(&strongarm_gpio_info);
- sysbus_register_withprop(&strongarm_ppc_info);
- sysbus_register_withprop(&strongarm_uart_info);
- sysbus_register_withprop(&strongarm_ssp_info);
+ type_register_static(&strongarm_pic_info);
+ type_register_static(&strongarm_rtc_sysbus_info);
+ type_register_static(&strongarm_gpio_info);
+ type_register_static(&strongarm_ppc_info);
+ type_register_static(&strongarm_uart_info);
+ type_register_static(&strongarm_ssp_info);
}
device_init(strongarm_register_devices)
diff --git a/hw/sun4c_intctl.c b/hw/sun4c_intctl.c
index e15b1674ce..081d6cc8bd 100644
--- a/hw/sun4c_intctl.c
+++ b/hw/sun4c_intctl.c
@@ -206,17 +206,26 @@ static int sun4c_intctl_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo sun4c_intctl_info = {
- .init = sun4c_intctl_init1,
- .qdev.name = "sun4c_intctl",
- .qdev.size = sizeof(Sun4c_INTCTLState),
- .qdev.vmsd = &vmstate_sun4c_intctl,
- .qdev.reset = sun4c_intctl_reset,
+static void sun4c_intctl_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = sun4c_intctl_init1;
+ dc->reset = sun4c_intctl_reset;
+ dc->vmsd = &vmstate_sun4c_intctl;
+}
+
+static TypeInfo sun4c_intctl_info = {
+ .name = "sun4c_intctl",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(Sun4c_INTCTLState),
+ .class_init = sun4c_intctl_class_init,
};
static void sun4c_intctl_register_devices(void)
{
- sysbus_register_withprop(&sun4c_intctl_info);
+ type_register_static(&sun4c_intctl_info);
}
device_init(sun4c_intctl_register_devices)
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 941cc98b9b..b79d14c35a 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -609,15 +609,23 @@ static int idreg_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo idreg_info = {
- .init = idreg_init1,
- .qdev.name = "macio_idreg",
- .qdev.size = sizeof(IDRegState),
+static void idreg_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = idreg_init1;
+}
+
+static TypeInfo idreg_info = {
+ .name = "macio_idreg",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IDRegState),
+ .class_init = idreg_class_init,
};
static void idreg_register_devices(void)
{
- sysbus_register_withprop(&idreg_info);
+ type_register_static(&idreg_info);
}
device_init(idreg_register_devices);
@@ -650,15 +658,23 @@ static int afx_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo afx_info = {
- .init = afx_init1,
- .qdev.name = "tcx_afx",
- .qdev.size = sizeof(AFXState),
+static void afx_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = afx_init1;
+}
+
+static TypeInfo afx_info = {
+ .name = "tcx_afx",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AFXState),
+ .class_init = afx_class_init,
};
static void afx_register_devices(void)
{
- sysbus_register_withprop(&afx_info);
+ type_register_static(&afx_info);
}
device_init(afx_register_devices);
@@ -720,18 +736,29 @@ static int prom_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo prom_info = {
- .init = prom_init1,
- .qdev.name = "openprom",
- .qdev.size = sizeof(PROMState),
- .qdev.props = (Property[]) {
- {/* end of property list */}
- }
+static Property prom_properties[] = {
+ {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = prom_init1;
+ dc->props = prom_properties;
+}
+
+static TypeInfo prom_info = {
+ .name = "openprom",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PROMState),
+ .class_init = prom_class_init,
};
static void prom_register_devices(void)
{
- sysbus_register_withprop(&prom_info);
+ type_register_static(&prom_info);
}
device_init(prom_register_devices);
@@ -779,19 +806,30 @@ static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size,
sysbus_mmio_map(s, 0, addr);
}
-static SysBusDeviceInfo ram_info = {
- .init = ram_init1,
- .qdev.name = "memory",
- .qdev.size = sizeof(RamDevice),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT64("size", RamDevice, size, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ram_properties[] = {
+ DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ram_init1;
+ dc->props = ram_properties;
+}
+
+static TypeInfo ram_info = {
+ .name = "memory",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RamDevice),
+ .class_init = ram_class_init,
};
static void ram_register_devices(void)
{
- sysbus_register_withprop(&ram_info);
+ type_register_static(&ram_info);
}
device_init(ram_register_devices);
diff --git a/hw/sun4m_iommu.c b/hw/sun4m_iommu.c
index ef7627c467..727532cb09 100644
--- a/hw/sun4m_iommu.c
+++ b/hw/sun4m_iommu.c
@@ -357,21 +357,32 @@ static int iommu_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo iommu_info = {
- .init = iommu_init1,
- .qdev.name = "iommu",
- .qdev.size = sizeof(IOMMUState),
- .qdev.vmsd = &vmstate_iommu,
- .qdev.reset = iommu_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property iommu_properties[] = {
+ DEFINE_PROP_HEX32("version", IOMMUState, version, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void iommu_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = iommu_init1;
+ dc->reset = iommu_reset;
+ dc->vmsd = &vmstate_iommu;
+ dc->props = iommu_properties;
+}
+
+static TypeInfo iommu_info = {
+ .name = "iommu",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(IOMMUState),
+ .class_init = iommu_class_init,
};
static void iommu_register_devices(void)
{
- sysbus_register_withprop(&iommu_info);
+ type_register_static(&iommu_info);
}
device_init(iommu_register_devices)
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 2dc3d0439f..79bbd495eb 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -562,19 +562,27 @@ pci_ebus_init1(PCIDevice *pci_dev)
return 0;
}
-static PCIDeviceInfo ebus_info = {
- .qdev.name = "ebus",
- .qdev.size = sizeof(EbusState),
- .init = pci_ebus_init1,
- .vendor_id = PCI_VENDOR_ID_SUN,
- .device_id = PCI_DEVICE_ID_SUN_EBUS,
- .revision = 0x01,
- .class_id = PCI_CLASS_BRIDGE_OTHER,
+static void ebus_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_ebus_init1;
+ k->vendor_id = PCI_VENDOR_ID_SUN;
+ k->device_id = PCI_DEVICE_ID_SUN_EBUS;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+}
+
+static TypeInfo ebus_info = {
+ .name = "ebus",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EbusState),
+ .class_init = ebus_class_init,
};
static void pci_ebus_register(void)
{
- pci_qdev_register(&ebus_info);
+ type_register_static(&ebus_info);
}
device_init(pci_ebus_register);
@@ -636,18 +644,29 @@ static int prom_init1(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo prom_info = {
- .init = prom_init1,
- .qdev.name = "openprom",
- .qdev.size = sizeof(PROMState),
- .qdev.props = (Property[]) {
- {/* end of property list */}
- }
+static Property prom_properties[] = {
+ {/* end of property list */},
+};
+
+static void prom_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = prom_init1;
+ dc->props = prom_properties;
+}
+
+static TypeInfo prom_info = {
+ .name = "openprom",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PROMState),
+ .class_init = prom_class_init,
};
static void prom_register_devices(void)
{
- sysbus_register_withprop(&prom_info);
+ type_register_static(&prom_info);
}
device_init(prom_register_devices);
@@ -688,19 +707,30 @@ static void ram_init(target_phys_addr_t addr, ram_addr_t RAM_size)
sysbus_mmio_map(s, 0, addr);
}
-static SysBusDeviceInfo ram_info = {
- .init = ram_init1,
- .qdev.name = "memory",
- .qdev.size = sizeof(RamDevice),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT64("size", RamDevice, size, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property ram_properties[] = {
+ DEFINE_PROP_UINT64("size", RamDevice, size, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ram_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = ram_init1;
+ dc->props = ram_properties;
+}
+
+static TypeInfo ram_info = {
+ .name = "memory",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(RamDevice),
+ .class_init = ram_class_init,
};
static void ram_register_devices(void)
{
- sysbus_register_withprop(&ram_info);
+ type_register_static(&ram_info);
}
device_init(ram_register_devices);
diff --git a/hw/sysbus.c b/hw/sysbus.c
index 2e06fe823c..282060abb6 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -105,31 +105,12 @@ void sysbus_init_ioports(SysBusDevice *dev, pio_addr_t ioport, pio_addr_t size)
}
}
-static int sysbus_device_init(DeviceState *dev, DeviceInfo *base)
+static int sysbus_device_init(DeviceState *dev)
{
- SysBusDeviceInfo *info = container_of(base, SysBusDeviceInfo, qdev);
+ SysBusDevice *sd = SYS_BUS_DEVICE(dev);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_GET_CLASS(sd);
- return info->init(sysbus_from_qdev(dev));
-}
-
-void sysbus_register_withprop(SysBusDeviceInfo *info)
-{
- info->qdev.init = sysbus_device_init;
- info->qdev.bus_info = &system_bus_info;
-
- assert(info->qdev.size >= sizeof(SysBusDevice));
- qdev_register(&info->qdev);
-}
-
-void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init)
-{
- SysBusDeviceInfo *info;
-
- info = g_malloc0(sizeof(*info));
- info->qdev.name = g_strdup(name);
- info->qdev.size = size;
- info->init = init;
- sysbus_register_withprop(info);
+ return sbc->init(sd);
}
DeviceState *sysbus_create_varargs(const char *name,
@@ -258,3 +239,26 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev)
{
return get_system_memory();
}
+
+static void sysbus_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = sysbus_device_init;
+ k->bus_info = &system_bus_info;
+}
+
+static TypeInfo sysbus_device_type_info = {
+ .name = TYPE_SYS_BUS_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .abstract = true,
+ .class_size = sizeof(SysBusDeviceClass),
+ .class_init = sysbus_device_class_init,
+};
+
+static void sysbus_register(void)
+{
+ type_register_static(&sysbus_device_type_info);
+}
+
+device_init(sysbus_register);
diff --git a/hw/sysbus.h b/hw/sysbus.h
index 7b8ca236bf..22555cd443 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -12,6 +12,20 @@
typedef struct SysBusDevice SysBusDevice;
+#define TYPE_SYS_BUS_DEVICE "sys-bus-device"
+#define SYS_BUS_DEVICE(obj) \
+ OBJECT_CHECK(SysBusDevice, (obj), TYPE_SYS_BUS_DEVICE)
+#define SYS_BUS_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SysBusDeviceClass, (klass), TYPE_SYS_BUS_DEVICE)
+#define SYS_BUS_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SysBusDeviceClass, (obj), TYPE_SYS_BUS_DEVICE)
+
+typedef struct SysBusDeviceClass {
+ DeviceClass parent_class;
+
+ int (*init)(SysBusDevice *dev);
+} SysBusDeviceClass;
+
struct SysBusDevice {
DeviceState qdev;
int num_irq;
@@ -26,19 +40,10 @@ struct SysBusDevice {
pio_addr_t pio[QDEV_MAX_PIO];
};
-typedef int (*sysbus_initfn)(SysBusDevice *dev);
-
/* Macros to compensate for lack of type inheritance in C. */
#define sysbus_from_qdev(dev) ((SysBusDevice *)(dev))
#define FROM_SYSBUS(type, dev) DO_UPCAST(type, busdev, dev)
-typedef struct {
- DeviceInfo qdev;
- sysbus_initfn init;
-} SysBusDeviceInfo;
-
-void sysbus_register_dev(const char *name, size_t size, sysbus_initfn init);
-void sysbus_register_withprop(SysBusDeviceInfo *info);
void *sysbus_new(void);
void sysbus_init_mmio(SysBusDevice *dev, MemoryRegion *memory);
MemoryRegion *sysbus_mmio_get_region(SysBusDevice *dev, int n);
diff --git a/hw/tcx.c b/hw/tcx.c
index 75a28f2ee5..ceb94c74a7 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -61,21 +61,13 @@ static void tcx24_screen_dump(void *opaque, const char *filename);
static void tcx_set_dirty(TCXState *s)
{
- unsigned int i;
-
- for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
- memory_region_set_dirty(&s->vram_mem, i);
- }
+ memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
}
static void tcx24_set_dirty(TCXState *s)
{
- unsigned int i;
-
- for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
- memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
- memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
- }
+ memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4);
+ memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4);
}
static void update_palette_entries(TCXState *s, int start, int end)
@@ -186,15 +178,13 @@ static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
ram_addr_t cpage)
{
int ret;
- unsigned int off;
-
- ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
- for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
- ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
- DIRTY_MEMORY_VGA);
- ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
- DIRTY_MEMORY_VGA);
- }
+
+ ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA);
+ ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
+ DIRTY_MEMORY_VGA);
+ ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
+ DIRTY_MEMORY_VGA);
return ret;
}
@@ -253,7 +243,8 @@ static void tcx_update_display(void *opaque)
}
for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
- if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
+ if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
+ DIRTY_MEMORY_VGA)) {
if (y_start < 0)
y_start = y;
if (page < page_min)
@@ -646,25 +637,36 @@ static void tcx24_screen_dump(void *opaque, const char *filename)
return;
}
-static SysBusDeviceInfo tcx_info = {
- .init = tcx_init1,
- .qdev.name = "SUNW,tcx",
- .qdev.size = sizeof(TCXState),
- .qdev.reset = tcx_reset,
- .qdev.vmsd = &vmstate_tcx,
- .qdev.props = (Property[]) {
- DEFINE_PROP_TADDR("addr", TCXState, addr, -1),
- DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
- DEFINE_PROP_UINT16("width", TCXState, width, -1),
- DEFINE_PROP_UINT16("height", TCXState, height, -1),
- DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property tcx_properties[] = {
+ DEFINE_PROP_TADDR("addr", TCXState, addr, -1),
+ DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
+ DEFINE_PROP_UINT16("width", TCXState, width, -1),
+ DEFINE_PROP_UINT16("height", TCXState, height, -1),
+ DEFINE_PROP_UINT16("depth", TCXState, depth, -1),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tcx_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = tcx_init1;
+ dc->reset = tcx_reset;
+ dc->vmsd = &vmstate_tcx;
+ dc->props = tcx_properties;
+}
+
+static TypeInfo tcx_info = {
+ .name = "SUNW,tcx",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TCXState),
+ .class_init = tcx_class_init,
};
static void tcx_register_devices(void)
{
- sysbus_register_withprop(&tcx_info);
+ type_register_static(&tcx_info);
}
device_init(tcx_register_devices)
diff --git a/hw/tmp105.c b/hw/tmp105.c
index f7e6f2b909..a3bdd91d40 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -22,7 +22,7 @@
#include "i2c.h"
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
uint8_t len;
uint8_t buf[2];
qemu_irq pin;
@@ -65,7 +65,7 @@ static void tmp105_alarm_update(TMP105State *s)
}
/* Units are 0.001 centigrades relative to 0 C. */
-void tmp105_set(i2c_slave *i2c, int temp)
+void tmp105_set(I2CSlave *i2c, int temp)
{
TMP105State *s = (TMP105State *) i2c;
@@ -138,7 +138,7 @@ static void tmp105_write(TMP105State *s)
}
}
-static int tmp105_rx(i2c_slave *i2c)
+static int tmp105_rx(I2CSlave *i2c)
{
TMP105State *s = (TMP105State *) i2c;
@@ -148,7 +148,7 @@ static int tmp105_rx(i2c_slave *i2c)
return 0xff;
}
-static int tmp105_tx(i2c_slave *i2c, uint8_t data)
+static int tmp105_tx(I2CSlave *i2c, uint8_t data)
{
TMP105State *s = (TMP105State *) i2c;
@@ -163,7 +163,7 @@ static int tmp105_tx(i2c_slave *i2c, uint8_t data)
return 0;
}
-static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
+static void tmp105_event(I2CSlave *i2c, enum i2c_event event)
{
TMP105State *s = (TMP105State *) i2c;
@@ -202,7 +202,7 @@ static const VMStateDescription vmstate_tmp105 = {
}
};
-static void tmp105_reset(i2c_slave *i2c)
+static void tmp105_reset(I2CSlave *i2c)
{
TMP105State *s = (TMP105State *) i2c;
@@ -215,7 +215,7 @@ static void tmp105_reset(i2c_slave *i2c)
tmp105_interrupt_update(s);
}
-static int tmp105_init(i2c_slave *i2c)
+static int tmp105_init(I2CSlave *i2c)
{
TMP105State *s = FROM_I2C_SLAVE(TMP105State, i2c);
@@ -226,19 +226,28 @@ static int tmp105_init(i2c_slave *i2c)
return 0;
}
-static I2CSlaveInfo tmp105_info = {
- .qdev.name = "tmp105",
- .qdev.size = sizeof(TMP105State),
- .qdev.vmsd = &vmstate_tmp105,
- .init = tmp105_init,
- .event = tmp105_event,
- .recv = tmp105_rx,
- .send = tmp105_tx
+static void tmp105_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = tmp105_init;
+ k->event = tmp105_event;
+ k->recv = tmp105_rx;
+ k->send = tmp105_tx;
+ dc->vmsd = &vmstate_tmp105;
+}
+
+static TypeInfo tmp105_info = {
+ .name = "tmp105",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(TMP105State),
+ .class_init = tmp105_class_init,
};
static void tmp105_register_devices(void)
{
- i2c_register_slave(&tmp105_info);
+ type_register_static(&tmp105_info);
}
device_init(tmp105_register_devices)
diff --git a/hw/tosa.c b/hw/tosa.c
index 0caba79c98..c0d401759e 100644
--- a/hw/tosa.c
+++ b/hw/tosa.c
@@ -133,12 +133,12 @@ static int tosa_ssp_init(SSISlave *dev)
}
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int len;
char buf[3];
} TosaDACState;
-static int tosa_dac_send(i2c_slave *i2c, uint8_t data)
+static int tosa_dac_send(I2CSlave *i2c, uint8_t data)
{
TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
s->buf[s->len] = data;
@@ -157,7 +157,7 @@ static int tosa_dac_send(i2c_slave *i2c, uint8_t data)
return 0;
}
-static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event)
+static void tosa_dac_event(I2CSlave *i2c, enum i2c_event event)
{
TosaDACState *s = FROM_I2C_SLAVE(TosaDACState, i2c);
s->len = 0;
@@ -180,13 +180,13 @@ static void tosa_dac_event(i2c_slave *i2c, enum i2c_event event)
}
}
-static int tosa_dac_recv(i2c_slave *s)
+static int tosa_dac_recv(I2CSlave *s)
{
printf("%s: recv not supported!!!\n", __FUNCTION__);
return -1;
}
-static int tosa_dac_init(i2c_slave *i2c)
+static int tosa_dac_init(I2CSlave *i2c)
{
/* Nothing to do. */
return 0;
@@ -259,26 +259,42 @@ static void tosapda_machine_init(void)
machine_init(tosapda_machine_init);
-static I2CSlaveInfo tosa_dac_info = {
- .qdev.name = "tosa_dac",
- .qdev.size = sizeof(TosaDACState),
- .init = tosa_dac_init,
- .event = tosa_dac_event,
- .recv = tosa_dac_recv,
- .send = tosa_dac_send
+static void tosa_dac_class_init(ObjectClass *klass, void *data)
+{
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = tosa_dac_init;
+ k->event = tosa_dac_event;
+ k->recv = tosa_dac_recv;
+ k->send = tosa_dac_send;
+}
+
+static TypeInfo tosa_dac_info = {
+ .name = "tosa_dac",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(TosaDACState),
+ .class_init = tosa_dac_class_init,
};
-static SSISlaveInfo tosa_ssp_info = {
- .qdev.name = "tosa-ssp",
- .qdev.size = sizeof(SSISlave),
- .init = tosa_ssp_init,
- .transfer = tosa_ssp_tansfer
+static void tosa_ssp_class_init(ObjectClass *klass, void *data)
+{
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = tosa_ssp_init;
+ k->transfer = tosa_ssp_tansfer;
+}
+
+static TypeInfo tosa_ssp_info = {
+ .name = "tosa-ssp",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(SSISlave),
+ .class_init = tosa_ssp_class_init,
};
static void tosa_register_devices(void)
{
- i2c_register_slave(&tosa_dac_info);
- ssi_register_slave(&tosa_ssp_info);
+ type_register_static(&tosa_dac_info);
+ type_register_static(&tosa_ssp_info);
}
device_init(tosa_register_devices)
diff --git a/hw/tusb6010.c b/hw/tusb6010.c
index 276300a302..0ade670906 100644
--- a/hw/tusb6010.c
+++ b/hw/tusb6010.c
@@ -789,16 +789,25 @@ static int tusb6010_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo tusb6010_info = {
- .init = tusb6010_init,
- .qdev.name = "tusb6010",
- .qdev.size = sizeof(TUSBState),
- .qdev.reset = tusb6010_reset,
+static void tusb6010_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = tusb6010_init;
+ dc->reset = tusb6010_reset;
+}
+
+static TypeInfo tusb6010_info = {
+ .name = "tusb6010",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(TUSBState),
+ .class_init = tusb6010_class_init,
};
static void tusb6010_register_device(void)
{
- sysbus_register_withprop(&tusb6010_info);
+ type_register_static(&tusb6010_info);
}
device_init(tusb6010_register_device)
diff --git a/hw/twl92230.c b/hw/twl92230.c
index a75448f06a..03fdccc8ce 100644
--- a/hw/twl92230.c
+++ b/hw/twl92230.c
@@ -27,7 +27,7 @@
#define VERBOSE 1
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int firstbyte;
uint8_t reg;
@@ -126,7 +126,7 @@ static void menelaus_rtc_hz(void *opaque)
menelaus_update(s);
}
-static void menelaus_reset(i2c_slave *i2c)
+static void menelaus_reset(I2CSlave *i2c)
{
MenelausState *s = (MenelausState *) i2c;
s->reg = 0x00;
@@ -709,7 +709,7 @@ static void menelaus_write(void *opaque, uint8_t addr, uint8_t value)
}
}
-static void menelaus_event(i2c_slave *i2c, enum i2c_event event)
+static void menelaus_event(I2CSlave *i2c, enum i2c_event event)
{
MenelausState *s = (MenelausState *) i2c;
@@ -717,7 +717,7 @@ static void menelaus_event(i2c_slave *i2c, enum i2c_event event)
s->firstbyte = 1;
}
-static int menelaus_tx(i2c_slave *i2c, uint8_t data)
+static int menelaus_tx(I2CSlave *i2c, uint8_t data)
{
MenelausState *s = (MenelausState *) i2c;
/* Interpret register address byte */
@@ -730,7 +730,7 @@ static int menelaus_tx(i2c_slave *i2c, uint8_t data)
return 0;
}
-static int menelaus_rx(i2c_slave *i2c)
+static int menelaus_rx(I2CSlave *i2c)
{
MenelausState *s = (MenelausState *) i2c;
@@ -842,7 +842,7 @@ static const VMStateDescription vmstate_menelaus = {
}
};
-static int twl92230_init(i2c_slave *i2c)
+static int twl92230_init(I2CSlave *i2c)
{
MenelausState *s = FROM_I2C_SLAVE(MenelausState, i2c);
@@ -857,19 +857,28 @@ static int twl92230_init(i2c_slave *i2c)
return 0;
}
-static I2CSlaveInfo twl92230_info = {
- .qdev.name ="twl92230",
- .qdev.size = sizeof(MenelausState),
- .qdev.vmsd = &vmstate_menelaus,
- .init = twl92230_init,
- .event = menelaus_event,
- .recv = menelaus_rx,
- .send = menelaus_tx
+static void twl92230_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ sc->init = twl92230_init;
+ sc->event = menelaus_event;
+ sc->recv = menelaus_rx;
+ sc->send = menelaus_tx;
+ dc->vmsd = &vmstate_menelaus;
+}
+
+static TypeInfo twl92230_info = {
+ .name = "twl92230",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(MenelausState),
+ .class_init = twl92230_class_init,
};
static void twl92230_register_devices(void)
{
- i2c_register_slave(&twl92230_info);
+ type_register_static(&twl92230_info);
}
device_init(twl92230_register_devices)
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 14d99147f3..17d86aac68 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -39,7 +39,6 @@
static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e };
typedef struct UNINState {
- SysBusDevice busdev;
PCIHostState host_state;
MemoryRegion pci_mmio;
MemoryRegion pci_hole;
@@ -64,10 +63,6 @@ static void pci_unin_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(pic[unin_irq_line[irq_num]], level);
}
-static void pci_unin_reset(void *opaque)
-{
-}
-
static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr)
{
uint32_t retval;
@@ -134,11 +129,13 @@ static const MemoryRegionOps unin_data_ops = {
static int pci_unin_main_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -147,17 +144,18 @@ static int pci_unin_main_init_device(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->host_state.conf_mem);
sysbus_init_mmio(dev, &s->host_state.data_mem);
- qemu_register_reset(pci_unin_reset, &s->host_state);
return 0;
}
static int pci_u3_agp_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Uninorth U3 AGP bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -166,17 +164,17 @@ static int pci_u3_agp_init_device(SysBusDevice *dev)
sysbus_init_mmio(dev, &s->host_state.conf_mem);
sysbus_init_mmio(dev, &s->host_state.data_mem);
- qemu_register_reset(pci_unin_reset, &s->host_state);
-
return 0;
}
static int pci_unin_agp_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Uninorth AGP bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -189,10 +187,12 @@ static int pci_unin_agp_init_device(SysBusDevice *dev)
static int pci_unin_internal_init_device(SysBusDevice *dev)
{
+ PCIHostState *h;
UNINState *s;
/* Uninorth internal bus */
- s = FROM_SYSBUS(UNINState, dev);
+ h = FROM_SYSBUS(PCIHostState, dev);
+ s = DO_UPCAST(UNINState, host_state, h);
memory_region_init_io(&s->host_state.conf_mem, &pci_host_conf_le_ops,
&s->host_state, "pci-conf-idx", 0x1000);
@@ -209,21 +209,23 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
{
DeviceState *dev;
SysBusDevice *s;
+ PCIHostState *h;
UNINState *d;
/* Use values found on a real PowerMac */
/* Uninorth main bus */
- dev = qdev_create(NULL, "uni-north");
+ dev = qdev_create(NULL, "uni-north-pci-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(UNINState, s);
+ h = FROM_SYSBUS(PCIHostState, s);
+ d = DO_UPCAST(UNINState, host_state, h);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
0x80000000ULL, 0x70000000ULL);
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+ d->host_state.bus = pci_register_bus(dev, "pci",
pci_unin_set_irq, pci_unin_map_irq,
pic,
&d->pci_mmio,
@@ -245,7 +247,7 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
/* Uninorth AGP bus */
pci_create_simple(d->host_state.bus, PCI_DEVFN(11, 0), "uni-north-agp");
- dev = qdev_create(NULL, "uni-north-agp");
+ dev = qdev_create(NULL, "uni-north-agp-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
sysbus_mmio_map(s, 0, 0xf0800000);
@@ -254,8 +256,9 @@ PCIBus *pci_pmac_init(qemu_irq *pic,
/* Uninorth internal bus */
#if 0
/* XXX: not needed for now */
- pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0), "uni-north-pci");
- dev = qdev_create(NULL, "uni-north-pci");
+ pci_create_simple(d->host_state.bus, PCI_DEVFN(14, 0),
+ "uni-north-internal-pci");
+ dev = qdev_create(NULL, "uni-north-internal-pci-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
sysbus_mmio_map(s, 0, 0xf4800000);
@@ -271,14 +274,16 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
{
DeviceState *dev;
SysBusDevice *s;
+ PCIHostState *h;
UNINState *d;
/* Uninorth AGP bus */
- dev = qdev_create(NULL, "u3-agp");
+ dev = qdev_create(NULL, "u3-agp-pcihost");
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
- d = FROM_SYSBUS(UNINState, s);
+ h = FROM_SYSBUS(PCIHostState, s);
+ d = DO_UPCAST(UNINState, host_state, h);
memory_region_init(&d->pci_mmio, "pci-mmio", 0x100000000ULL);
memory_region_init_alias(&d->pci_hole, "pci-hole", &d->pci_mmio,
@@ -286,7 +291,7 @@ PCIBus *pci_pmac_u3_init(qemu_irq *pic,
memory_region_add_subregion(address_space_mem, 0x80000000ULL,
&d->pci_hole);
- d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci",
+ d->host_state.bus = pci_register_bus(dev, "pci",
pci_unin_set_irq, pci_unin_map_irq,
pic,
&d->pci_mmio,
@@ -334,60 +339,145 @@ static int unin_internal_pci_host_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo unin_main_pci_host_info = {
- .qdev.name = "uni-north",
- .qdev.size = sizeof(PCIDevice),
- .init = unin_main_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void unin_main_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = unin_main_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_PCI;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_main_pci_host_info = {
+ .name = "uni-north-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = unin_main_pci_host_class_init,
+};
+
+static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = u3_agp_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_U3_AGP;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo u3_agp_pci_host_info = {
+ .name = "u3-agp",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = u3_agp_pci_host_class_init,
+};
+
+static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = unin_agp_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_agp_pci_host_info = {
+ .name = "uni-north-agp",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = unin_agp_pci_host_class_init,
+};
+
+static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = unin_internal_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI;
+ k->revision = 0x00;
+ k->class_id = PCI_CLASS_BRIDGE_HOST;
+}
+
+static TypeInfo unin_internal_pci_host_info = {
+ .name = "uni-north-internal-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = unin_internal_pci_host_class_init,
};
-static PCIDeviceInfo u3_agp_pci_host_info = {
- .qdev.name = "u3-agp",
- .qdev.size = sizeof(PCIDevice),
- .init = u3_agp_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_U3_AGP,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void pci_unin_main_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_unin_main_init_device;
+}
+
+static TypeInfo pci_unin_main_info = {
+ .name = "uni-north-pci-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_unin_main_class_init,
+};
+
+static void pci_u3_agp_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_u3_agp_init_device;
+}
+
+static TypeInfo pci_u3_agp_info = {
+ .name = "u3-agp-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_u3_agp_class_init,
};
-static PCIDeviceInfo unin_agp_pci_host_info = {
- .qdev.name = "uni-north-agp",
- .qdev.size = sizeof(PCIDevice),
- .init = unin_agp_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_UNI_N_AGP,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void pci_unin_agp_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_unin_agp_init_device;
+}
+
+static TypeInfo pci_unin_agp_info = {
+ .name = "uni-north-agp-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_unin_agp_class_init,
};
-static PCIDeviceInfo unin_internal_pci_host_info = {
- .qdev.name = "uni-north-pci",
- .qdev.size = sizeof(PCIDevice),
- .init = unin_internal_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_UNI_N_I_PCI,
- .revision = 0x00,
- .class_id = PCI_CLASS_BRIDGE_HOST,
+static void pci_unin_internal_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = pci_unin_internal_init_device;
+}
+
+static TypeInfo pci_unin_internal_info = {
+ .name = "uni-north-internal-pci-pcihost",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(UNINState),
+ .class_init = pci_unin_internal_class_init,
};
static void unin_register_devices(void)
{
- sysbus_register_dev("uni-north", sizeof(UNINState),
- pci_unin_main_init_device);
- pci_qdev_register(&unin_main_pci_host_info);
- sysbus_register_dev("u3-agp", sizeof(UNINState),
- pci_u3_agp_init_device);
- pci_qdev_register(&u3_agp_pci_host_info);
- sysbus_register_dev("uni-north-agp", sizeof(UNINState),
- pci_unin_agp_init_device);
- pci_qdev_register(&unin_agp_pci_host_info);
- sysbus_register_dev("uni-north-pci", sizeof(UNINState),
- pci_unin_internal_init_device);
- pci_qdev_register(&unin_internal_pci_host_info);
+ type_register_static(&unin_main_pci_host_info);
+ type_register_static(&u3_agp_pci_host_info);
+ type_register_static(&unin_agp_pci_host_info);
+ type_register_static(&unin_internal_pci_host_info);
+
+ type_register_static(&pci_unin_main_info);
+ type_register_static(&pci_u3_agp_info);
+ type_register_static(&pci_unin_agp_info);
+ type_register_static(&pci_unin_internal_info);
}
device_init(unin_register_devices)
diff --git a/hw/usb-audio.c b/hw/usb-audio.c
new file mode 100644
index 0000000000..cd589b718a
--- /dev/null
+++ b/hw/usb-audio.c
@@ -0,0 +1,715 @@
+/*
+ * QEMU USB audio device
+ *
+ * written by:
+ * H. Peter Anvin <hpa@linux.intel.com>
+ * Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * lousely based on usb net device code which is:
+ *
+ * Copyright (c) 2006 Thomas Sailer
+ * Copyright (c) 2008 Andrzej Zaborowski
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu-common.h"
+#include "usb.h"
+#include "usb-desc.h"
+#include "hw.h"
+#include "audiodev.h"
+#include "audio/audio.h"
+
+#define USBAUDIO_VENDOR_NUM 0x46f4 /* CRC16() of "QEMU" */
+#define USBAUDIO_PRODUCT_NUM 0x0002
+
+#define DEV_CONFIG_VALUE 1 /* The one and only */
+
+/* Descriptor subtypes for AC interfaces */
+#define DST_AC_HEADER 1
+#define DST_AC_INPUT_TERMINAL 2
+#define DST_AC_OUTPUT_TERMINAL 3
+#define DST_AC_FEATURE_UNIT 6
+/* Descriptor subtypes for AS interfaces */
+#define DST_AS_GENERAL 1
+#define DST_AS_FORMAT_TYPE 2
+/* Descriptor subtypes for endpoints */
+#define DST_EP_GENERAL 1
+
+enum usb_audio_strings {
+ STRING_NULL,
+ STRING_MANUFACTURER,
+ STRING_PRODUCT,
+ STRING_SERIALNUMBER,
+ STRING_CONFIG,
+ STRING_USBAUDIO_CONTROL,
+ STRING_INPUT_TERMINAL,
+ STRING_FEATURE_UNIT,
+ STRING_OUTPUT_TERMINAL,
+ STRING_NULL_STREAM,
+ STRING_REAL_STREAM,
+};
+
+static const USBDescStrings usb_audio_stringtable = {
+ [STRING_MANUFACTURER] = "QEMU",
+ [STRING_PRODUCT] = "QEMU USB Audio",
+ [STRING_SERIALNUMBER] = "1",
+ [STRING_CONFIG] = "Audio Configuration",
+ [STRING_USBAUDIO_CONTROL] = "Audio Device",
+ [STRING_INPUT_TERMINAL] = "Audio Output Pipe",
+ [STRING_FEATURE_UNIT] = "Audio Output Volume Control",
+ [STRING_OUTPUT_TERMINAL] = "Audio Output Terminal",
+ [STRING_NULL_STREAM] = "Audio Output - Disabled",
+ [STRING_REAL_STREAM] = "Audio Output - 48 kHz Stereo",
+};
+
+#define U16(x) ((x) & 0xff), (((x) >> 8) & 0xff)
+#define U24(x) U16(x), (((x) >> 16) & 0xff)
+#define U32(x) U24(x), (((x) >> 24) & 0xff)
+
+/*
+ * A Basic Audio Device uses these specific values
+ */
+#define USBAUDIO_PACKET_SIZE 192
+#define USBAUDIO_SAMPLE_RATE 48000
+#define USBAUDIO_PACKET_INTERVAL 1
+
+static const USBDescIface desc_iface[] = {
+ {
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL,
+ .bInterfaceProtocol = 0x04,
+ .iInterface = STRING_USBAUDIO_CONTROL,
+ .ndesc = 4,
+ .descs = (USBDescOther[]) {
+ {
+ /* Headphone Class-Specific AC Interface Header Descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_HEADER, /* u8 bDescriptorSubtype */
+ U16(0x0100), /* u16 bcdADC */
+ U16(0x2b), /* u16 wTotalLength */
+ 0x01, /* u8 bInCollection */
+ 0x01, /* u8 baInterfaceNr */
+ }
+ },{
+ /* Generic Stereo Input Terminal ID1 Descriptor */
+ .data = (uint8_t[]) {
+ 0x0c, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_INPUT_TERMINAL, /* u8 bDescriptorSubtype */
+ 0x01, /* u8 bTerminalID */
+ U16(0x0101), /* u16 wTerminalType */
+ 0x00, /* u8 bAssocTerminal */
+ 0x02, /* u16 bNrChannels */
+ U16(0x0003), /* u16 wChannelConfig */
+ 0x00, /* u8 iChannelNames */
+ STRING_INPUT_TERMINAL, /* u8 iTerminal */
+ }
+ },{
+ /* Generic Stereo Feature Unit ID2 Descriptor */
+ .data = (uint8_t[]) {
+ 0x0d, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_FEATURE_UNIT, /* u8 bDescriptorSubtype */
+ 0x02, /* u8 bUnitID */
+ 0x01, /* u8 bSourceID */
+ 0x02, /* u8 bControlSize */
+ U16(0x0001), /* u16 bmaControls(0) */
+ U16(0x0002), /* u16 bmaControls(1) */
+ U16(0x0002), /* u16 bmaControls(2) */
+ STRING_FEATURE_UNIT, /* u8 iFeature */
+ }
+ },{
+ /* Headphone Ouptut Terminal ID3 Descriptor */
+ .data = (uint8_t[]) {
+ 0x09, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AC_OUTPUT_TERMINAL, /* u8 bDescriptorSubtype */
+ 0x03, /* u8 bUnitID */
+ U16(0x0301), /* u16 wTerminalType (SPK) */
+ 0x00, /* u8 bAssocTerminal */
+ 0x02, /* u8 bSourceID */
+ STRING_OUTPUT_TERMINAL, /* u8 iTerminal */
+ }
+ }
+ },
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
+ .iInterface = STRING_NULL_STREAM,
+ },{
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_STREAMING,
+ .iInterface = STRING_REAL_STREAM,
+ .ndesc = 2,
+ .descs = (USBDescOther[]) {
+ {
+ /* Headphone Class-specific AS General Interface Descriptor */
+ .data = (uint8_t[]) {
+ 0x07, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AS_GENERAL, /* u8 bDescriptorSubtype */
+ 0x01, /* u8 bTerminalLink */
+ 0x00, /* u8 bDelay */
+ 0x01, 0x00, /* u16 wFormatTag */
+ }
+ },{
+ /* Headphone Type I Format Type Descriptor */
+ .data = (uint8_t[]) {
+ 0x0b, /* u8 bLength */
+ USB_DT_CS_INTERFACE, /* u8 bDescriptorType */
+ DST_AS_FORMAT_TYPE, /* u8 bDescriptorSubtype */
+ 0x01, /* u8 bFormatType */
+ 0x02, /* u8 bNrChannels */
+ 0x02, /* u8 bSubFrameSize */
+ 0x10, /* u8 bBitResolution */
+ 0x01, /* u8 bSamFreqType */
+ U24(USBAUDIO_SAMPLE_RATE), /* u24 tSamFreq */
+ }
+ }
+ },
+ .eps = (USBDescEndpoint[]) {
+ {
+ .bEndpointAddress = USB_DIR_OUT | 0x01,
+ .bmAttributes = 0x0d,
+ .wMaxPacketSize = USBAUDIO_PACKET_SIZE,
+ .bInterval = 1,
+ .is_audio = 1,
+ /* Stereo Headphone Class-specific
+ AS Audio Data Endpoint Descriptor */
+ .extra = (uint8_t[]) {
+ 0x07, /* u8 bLength */
+ USB_DT_CS_ENDPOINT, /* u8 bDescriptorType */
+ DST_EP_GENERAL, /* u8 bDescriptorSubtype */
+ 0x00, /* u8 bmAttributes */
+ 0x00, /* u8 bLockDelayUnits */
+ U16(0x0000), /* u16 wLockDelay */
+ },
+ },
+ }
+ }
+};
+
+static const USBDescDevice desc_device = {
+ .bcdUSB = 0x0200,
+ .bMaxPacketSize0 = 64,
+ .bNumConfigurations = 1,
+ .confs = (USBDescConfig[]) {
+ {
+ .bNumInterfaces = 2,
+ .bConfigurationValue = DEV_CONFIG_VALUE,
+ .iConfiguration = STRING_CONFIG,
+ .bmAttributes = 0xc0,
+ .bMaxPower = 0x32,
+ .nif = ARRAY_SIZE(desc_iface),
+ .ifs = desc_iface,
+ },
+ },
+};
+
+static const USBDesc desc_audio = {
+ .id = {
+ .idVendor = USBAUDIO_VENDOR_NUM,
+ .idProduct = USBAUDIO_PRODUCT_NUM,
+ .bcdDevice = 0,
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .iSerialNumber = STRING_SERIALNUMBER,
+ },
+ .full = &desc_device,
+ .str = usb_audio_stringtable,
+};
+
+/*
+ * A USB audio device supports an arbitrary number of alternate
+ * interface settings for each interface. Each corresponds to a block
+ * diagram of parameterized blocks. This can thus refer to things like
+ * number of channels, data rates, or in fact completely different
+ * block diagrams. Alternative setting 0 is always the null block diagram,
+ * which is used by a disabled device.
+ */
+enum usb_audio_altset {
+ ALTSET_OFF = 0x00, /* No endpoint */
+ ALTSET_ON = 0x01, /* Single endpoint */
+};
+
+/*
+ * Class-specific control requests
+ */
+#define CR_SET_CUR 0x01
+#define CR_GET_CUR 0x81
+#define CR_SET_MIN 0x02
+#define CR_GET_MIN 0x82
+#define CR_SET_MAX 0x03
+#define CR_GET_MAX 0x83
+#define CR_SET_RES 0x04
+#define CR_GET_RES 0x84
+#define CR_SET_MEM 0x05
+#define CR_GET_MEM 0x85
+#define CR_GET_STAT 0xff
+
+/*
+ * Feature Unit Control Selectors
+ */
+#define MUTE_CONTROL 0x01
+#define VOLUME_CONTROL 0x02
+#define BASS_CONTROL 0x03
+#define MID_CONTROL 0x04
+#define TREBLE_CONTROL 0x05
+#define GRAPHIC_EQUALIZER_CONTROL 0x06
+#define AUTOMATIC_GAIN_CONTROL 0x07
+#define DELAY_CONTROL 0x08
+#define BASS_BOOST_CONTROL 0x09
+#define LOUDNESS_CONTROL 0x0a
+
+/*
+ * buffering
+ */
+
+struct streambuf {
+ uint8_t *data;
+ uint32_t size;
+ uint32_t prod;
+ uint32_t cons;
+};
+
+static void streambuf_init(struct streambuf *buf, uint32_t size)
+{
+ g_free(buf->data);
+ buf->size = size - (size % USBAUDIO_PACKET_SIZE);
+ buf->data = g_malloc(buf->size);
+ buf->prod = 0;
+ buf->cons = 0;
+}
+
+static void streambuf_fini(struct streambuf *buf)
+{
+ g_free(buf->data);
+ buf->data = NULL;
+}
+
+static int streambuf_put(struct streambuf *buf, USBPacket *p)
+{
+ uint32_t free = buf->size - (buf->prod - buf->cons);
+
+ if (!free) {
+ return 0;
+ }
+ assert(free >= USBAUDIO_PACKET_SIZE);
+ usb_packet_copy(p, buf->data + (buf->prod % buf->size),
+ USBAUDIO_PACKET_SIZE);
+ buf->prod += USBAUDIO_PACKET_SIZE;
+ return USBAUDIO_PACKET_SIZE;
+}
+
+static uint8_t *streambuf_get(struct streambuf *buf)
+{
+ uint32_t used = buf->prod - buf->cons;
+ uint8_t *data;
+
+ if (!used) {
+ return NULL;
+ }
+ assert(used >= USBAUDIO_PACKET_SIZE);
+ data = buf->data + (buf->cons % buf->size);
+ buf->cons += USBAUDIO_PACKET_SIZE;
+ return data;
+}
+
+typedef struct USBAudioState {
+ /* qemu interfaces */
+ USBDevice dev;
+ QEMUSoundCard card;
+
+ /* state */
+ struct {
+ enum usb_audio_altset altset;
+ struct audsettings as;
+ SWVoiceOut *voice;
+ bool mute;
+ uint8_t vol[2];
+ struct streambuf buf;
+ } out;
+
+ /* properties */
+ uint32_t debug;
+ uint32_t buffer;
+} USBAudioState;
+
+static void output_callback(void *opaque, int avail)
+{
+ USBAudioState *s = opaque;
+ uint8_t *data;
+
+ for (;;) {
+ if (avail < USBAUDIO_PACKET_SIZE) {
+ return;
+ }
+ data = streambuf_get(&s->out.buf);
+ if (NULL == data) {
+ return;
+ }
+ AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
+ avail -= USBAUDIO_PACKET_SIZE;
+ }
+}
+
+static int usb_audio_set_output_altset(USBAudioState *s, int altset)
+{
+ switch (altset) {
+ case ALTSET_OFF:
+ streambuf_init(&s->out.buf, s->buffer);
+ AUD_set_active_out(s->out.voice, false);
+ break;
+ case ALTSET_ON:
+ AUD_set_active_out(s->out.voice, true);
+ break;
+ default:
+ return -1;
+ }
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: set interface %d\n", altset);
+ }
+ s->out.altset = altset;
+ return 0;
+}
+
+/*
+ * Note: we arbitrarily map the volume control range onto -inf..+8 dB
+ */
+#define ATTRIB_ID(cs, attrib, idif) \
+ (((cs) << 24) | ((attrib) << 16) | (idif))
+
+static int usb_audio_get_control(USBAudioState *s, uint8_t attrib,
+ uint16_t cscn, uint16_t idif,
+ int length, uint8_t *data)
+{
+ uint8_t cs = cscn >> 8;
+ uint8_t cn = cscn - 1; /* -1 for the non-present master control */
+ uint32_t aid = ATTRIB_ID(cs, attrib, idif);
+ int ret = USB_RET_STALL;
+
+ switch (aid) {
+ case ATTRIB_ID(MUTE_CONTROL, CR_GET_CUR, 0x0200):
+ data[0] = s->out.mute;
+ ret = 1;
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_CUR, 0x0200):
+ if (cn < 2) {
+ uint16_t vol = (s->out.vol[cn] * 0x8800 + 127) / 255 + 0x8000;
+ data[0] = vol;
+ data[1] = vol >> 8;
+ ret = 2;
+ }
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MIN, 0x0200):
+ if (cn < 2) {
+ data[0] = 0x01;
+ data[1] = 0x80;
+ ret = 2;
+ }
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_MAX, 0x0200):
+ if (cn < 2) {
+ data[0] = 0x00;
+ data[1] = 0x08;
+ ret = 2;
+ }
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_GET_RES, 0x0200):
+ if (cn < 2) {
+ data[0] = 0x88;
+ data[1] = 0x00;
+ ret = 2;
+ }
+ break;
+ }
+
+ return ret;
+}
+static int usb_audio_set_control(USBAudioState *s, uint8_t attrib,
+ uint16_t cscn, uint16_t idif,
+ int length, uint8_t *data)
+{
+ uint8_t cs = cscn >> 8;
+ uint8_t cn = cscn - 1; /* -1 for the non-present master control */
+ uint32_t aid = ATTRIB_ID(cs, attrib, idif);
+ int ret = USB_RET_STALL;
+ bool set_vol = false;
+
+ switch (aid) {
+ case ATTRIB_ID(MUTE_CONTROL, CR_SET_CUR, 0x0200):
+ s->out.mute = data[0] & 1;
+ set_vol = true;
+ ret = 0;
+ break;
+ case ATTRIB_ID(VOLUME_CONTROL, CR_SET_CUR, 0x0200):
+ if (cn < 2) {
+ uint16_t vol = data[0] + (data[1] << 8);
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: vol %04x\n", (uint16_t)vol);
+ }
+
+ vol -= 0x8000;
+ vol = (vol * 255 + 0x4400) / 0x8800;
+ if (vol > 255) {
+ vol = 255;
+ }
+
+ s->out.vol[cn] = vol;
+ set_vol = true;
+ ret = 0;
+ }
+ break;
+ }
+
+ if (set_vol) {
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: mute %d, lvol %3d, rvol %3d\n",
+ s->out.mute, s->out.vol[0], s->out.vol[1]);
+ }
+ AUD_set_volume_out(s->out.voice, s->out.mute,
+ s->out.vol[0], s->out.vol[1]);
+ }
+
+ return ret;
+}
+
+static int usb_audio_handle_control(USBDevice *dev, USBPacket *p,
+ int request, int value, int index,
+ int length, uint8_t *data)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+ int ret = 0;
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: control transaction: "
+ "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
+ request, value, index, length);
+ }
+
+ ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
+ if (ret >= 0) {
+ return ret;
+ }
+
+ switch (request) {
+ case ClassInterfaceRequest | CR_GET_CUR:
+ case ClassInterfaceRequest | CR_GET_MIN:
+ case ClassInterfaceRequest | CR_GET_MAX:
+ case ClassInterfaceRequest | CR_GET_RES:
+ ret = usb_audio_get_control(s, request & 0xff, value, index,
+ length, data);
+ if (ret < 0) {
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: fail: get control\n");
+ }
+ goto fail;
+ }
+ break;
+
+ case ClassInterfaceOutRequest | CR_SET_CUR:
+ case ClassInterfaceOutRequest | CR_SET_MIN:
+ case ClassInterfaceOutRequest | CR_SET_MAX:
+ case ClassInterfaceOutRequest | CR_SET_RES:
+ ret = usb_audio_set_control(s, request & 0xff, value, index,
+ length, data);
+ if (ret < 0) {
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: fail: set control\n");
+ }
+ goto fail;
+ }
+ break;
+
+ default:
+fail:
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: failed control transaction: "
+ "request 0x%04x value 0x%04x index 0x%04x length 0x%04x\n",
+ request, value, index, length);
+ }
+ ret = USB_RET_STALL;
+ break;
+ }
+ return ret;
+}
+
+static void usb_audio_set_interface(USBDevice *dev, int iface,
+ int old, int value)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ if (iface == 1) {
+ usb_audio_set_output_altset(s, value);
+ }
+}
+
+static void usb_audio_handle_reset(USBDevice *dev)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: reset\n");
+ }
+ usb_audio_set_output_altset(s, ALTSET_OFF);
+}
+
+static int usb_audio_handle_dataout(USBAudioState *s, USBPacket *p)
+{
+ int rc;
+
+ if (s->out.altset == ALTSET_OFF) {
+ return USB_RET_STALL;
+ }
+
+ rc = streambuf_put(&s->out.buf, p);
+ if (rc < p->iov.size && s->debug > 1) {
+ fprintf(stderr, "usb-audio: output overrun (%zd bytes)\n",
+ p->iov.size - rc);
+ }
+
+ return 0;
+}
+
+static int usb_audio_handle_data(USBDevice *dev, USBPacket *p)
+{
+ USBAudioState *s = (USBAudioState *) dev;
+ int ret = 0;
+
+ switch (p->pid) {
+ case USB_TOKEN_OUT:
+ switch (p->devep) {
+ case 1:
+ ret = usb_audio_handle_dataout(s, p);
+ break;
+ default:
+ goto fail;
+ }
+ break;
+
+ default:
+fail:
+ ret = USB_RET_STALL;
+ break;
+ }
+ if (ret == USB_RET_STALL && s->debug) {
+ fprintf(stderr, "usb-audio: failed data transaction: "
+ "pid 0x%x ep 0x%x len 0x%zx\n",
+ p->pid, p->devep, p->iov.size);
+ }
+ return ret;
+}
+
+static void usb_audio_handle_destroy(USBDevice *dev)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ if (s->debug) {
+ fprintf(stderr, "usb-audio: destroy\n");
+ }
+
+ usb_audio_set_output_altset(s, ALTSET_OFF);
+ AUD_close_out(&s->card, s->out.voice);
+ AUD_remove_card(&s->card);
+
+ streambuf_fini(&s->out.buf);
+}
+
+static int usb_audio_initfn(USBDevice *dev)
+{
+ USBAudioState *s = DO_UPCAST(USBAudioState, dev, dev);
+
+ usb_desc_init(dev);
+ s->dev.opaque = s;
+ AUD_register_card("usb-audio", &s->card);
+
+ s->out.altset = ALTSET_OFF;
+ s->out.mute = false;
+ s->out.vol[0] = 240; /* 0 dB */
+ s->out.vol[1] = 240; /* 0 dB */
+ s->out.as.freq = USBAUDIO_SAMPLE_RATE;
+ s->out.as.nchannels = 2;
+ s->out.as.fmt = AUD_FMT_S16;
+ s->out.as.endianness = 0;
+ streambuf_init(&s->out.buf, s->buffer);
+
+ s->out.voice = AUD_open_out(&s->card, s->out.voice, "usb-audio",
+ s, output_callback, &s->out.as);
+ AUD_set_volume_out(s->out.voice, s->out.mute, s->out.vol[0], s->out.vol[1]);
+ AUD_set_active_out(s->out.voice, 0);
+ return 0;
+}
+
+static const VMStateDescription vmstate_usb_audio = {
+ .name = "usb-audio",
+ .unmigratable = 1,
+};
+
+static Property usb_audio_properties[] = {
+ DEFINE_PROP_UINT32("debug", USBAudioState, debug, 0),
+ DEFINE_PROP_UINT32("buffer", USBAudioState, buffer,
+ 8 * USBAUDIO_PACKET_SIZE),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_audio_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *k = USB_DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_usb_audio;
+ dc->props = usb_audio_properties;
+ k->product_desc = "QEMU USB Audio Interface";
+ k->usb_desc = &desc_audio;
+ k->init = usb_audio_initfn;
+ k->handle_packet = usb_generic_handle_packet;
+ k->handle_reset = usb_audio_handle_reset;
+ k->handle_control = usb_audio_handle_control;
+ k->handle_data = usb_audio_handle_data;
+ k->handle_destroy = usb_audio_handle_destroy;
+ k->set_interface = usb_audio_set_interface;
+}
+
+static TypeInfo usb_audio_info = {
+ .name = "usb-audio",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBAudioState),
+ .class_init = usb_audio_class_init,
+};
+
+static void usb_audio_register_devices(void)
+{
+ type_register_static(&usb_audio_info);
+ usb_legacy_register("usb-audio", "audio", NULL);
+}
+
+device_init(usb_audio_register_devices)
diff --git a/hw/usb-bt.c b/hw/usb-bt.c
index f30eec1ea2..90c3b0e0eb 100644
--- a/hw/usb-bt.c
+++ b/hw/usb-bt.c
@@ -28,7 +28,6 @@ struct USBBtState {
USBDevice dev;
struct HCIInfo *hci;
- int altsetting;
int config;
#define CFIFO_LEN_MASK 255
@@ -362,7 +361,6 @@ static void usb_bt_handle_reset(USBDevice *dev)
s->outcmd.len = 0;
s->outacl.len = 0;
s->outsco.len = 0;
- s->altsetting = 0;
}
static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
@@ -402,26 +400,6 @@ static int usb_bt_handle_control(USBDevice *dev, USBPacket *p,
case EndpointOutRequest | USB_REQ_SET_FEATURE:
goto fail;
break;
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- if (value != 0 || (index & ~1) || length != 1)
- goto fail;
- if (index == 1)
- data[0] = s->altsetting;
- else
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- if ((index & ~1) || length != 0 ||
- (index == 1 && (value < 0 || value > 4)) ||
- (index == 0 && value != 0)) {
- printf("%s: Wrong SET_INTERFACE request (%i, %i)\n",
- __FUNCTION__, index, value);
- goto fail;
- }
- s->altsetting = value;
- ret = 0;
- break;
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE) << 8):
if (s->config)
usb_bt_fifo_out_enqueue(s, &s->outcmd, s->hci->cmd_send,
@@ -549,22 +527,31 @@ static const VMStateDescription vmstate_usb_bt = {
.unmigratable = 1,
};
-static struct USBDeviceInfo bt_info = {
- .product_desc = "QEMU BT dongle",
- .qdev.name = "usb-bt-dongle",
- .qdev.size = sizeof(struct USBBtState),
- .qdev.vmsd = &vmstate_usb_bt,
- .usb_desc = &desc_bluetooth,
- .init = usb_bt_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_bt_handle_reset,
- .handle_control = usb_bt_handle_control,
- .handle_data = usb_bt_handle_data,
- .handle_destroy = usb_bt_handle_destroy,
+static void usb_bt_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_bt_initfn;
+ uc->product_desc = "QEMU BT dongle";
+ uc->usb_desc = &desc_bluetooth;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_bt_handle_reset;
+ uc->handle_control = usb_bt_handle_control;
+ uc->handle_data = usb_bt_handle_data;
+ uc->handle_destroy = usb_bt_handle_destroy;
+ dc->vmsd = &vmstate_usb_bt;
+}
+
+static TypeInfo bt_info = {
+ .name = "usb-bt-dongle",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(struct USBBtState),
+ .class_init = usb_bt_class_initfn,
};
static void usb_bt_register_devices(void)
{
- usb_qdev_register(&bt_info);
+ type_register_static(&bt_info);
}
device_init(usb_bt_register_devices)
diff --git a/hw/usb-bus.c b/hw/usb-bus.c
index bd4afa7e2b..b753834584 100644
--- a/hw/usb-bus.c
+++ b/hw/usb-bus.c
@@ -65,21 +65,112 @@ USBBus *usb_bus_find(int busnr)
return NULL;
}
-static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int usb_device_init(USBDevice *dev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
- USBDeviceInfo *info = DO_UPCAST(USBDeviceInfo, qdev, base);
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->init) {
+ return klass->init(dev);
+ }
+ return 0;
+}
+
+static void usb_device_handle_destroy(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_destroy) {
+ klass->handle_destroy(dev);
+ }
+}
+
+int usb_device_handle_packet(USBDevice *dev, USBPacket *p)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_packet) {
+ return klass->handle_packet(dev, p);
+ }
+ return -ENOSYS;
+}
+
+void usb_device_cancel_packet(USBDevice *dev, USBPacket *p)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->cancel_packet) {
+ klass->cancel_packet(dev, p);
+ }
+}
+
+void usb_device_handle_attach(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_attach) {
+ klass->handle_attach(dev);
+ }
+}
+
+void usb_device_handle_reset(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_reset) {
+ klass->handle_reset(dev);
+ }
+}
+
+int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request,
+ int value, int index, int length, uint8_t *data)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_control) {
+ return klass->handle_control(dev, p, request, value, index, length,
+ data);
+ }
+ return -ENOSYS;
+}
+
+int usb_device_handle_data(USBDevice *dev, USBPacket *p)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->handle_data) {
+ return klass->handle_data(dev, p);
+ }
+ return -ENOSYS;
+}
+
+const char *usb_device_get_product_desc(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ return klass->product_desc;
+}
+
+const USBDesc *usb_device_get_usb_desc(USBDevice *dev)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ return klass->usb_desc;
+}
+
+void usb_device_set_interface(USBDevice *dev, int interface,
+ int alt_old, int alt_new)
+{
+ USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev);
+ if (klass->set_interface) {
+ klass->set_interface(dev, interface, alt_old, alt_new);
+ }
+}
+
+static int usb_qdev_init(DeviceState *qdev)
+{
+ USBDevice *dev = USB_DEVICE(qdev);
int rc;
- pstrcpy(dev->product_desc, sizeof(dev->product_desc), info->product_desc);
- dev->info = info;
+ pstrcpy(dev->product_desc, sizeof(dev->product_desc),
+ usb_device_get_product_desc(dev));
dev->auto_attach = 1;
QLIST_INIT(&dev->strings);
+ usb_ep_init(dev);
rc = usb_claim_port(dev);
if (rc != 0) {
return rc;
}
- rc = dev->info->init(dev);
+ rc = usb_device_init(dev);
if (rc != 0) {
usb_release_port(dev);
return rc;
@@ -96,34 +187,36 @@ static int usb_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int usb_qdev_exit(DeviceState *qdev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
if (dev->attached) {
usb_device_detach(dev);
}
- if (dev->info->handle_destroy) {
- dev->info->handle_destroy(dev);
- }
+ usb_device_handle_destroy(dev);
if (dev->port) {
usb_release_port(dev);
}
return 0;
}
-void usb_qdev_register(USBDeviceInfo *info)
+typedef struct LegacyUSBFactory
{
- info->qdev.bus_info = &usb_bus_info;
- info->qdev.init = usb_qdev_init;
- info->qdev.unplug = qdev_simple_unplug_cb;
- info->qdev.exit = usb_qdev_exit;
- qdev_register(&info->qdev);
-}
+ const char *name;
+ const char *usbdevice_name;
+ USBDevice *(*usbdevice_init)(const char *params);
+} LegacyUSBFactory;
-void usb_qdev_register_many(USBDeviceInfo *info)
+static GSList *legacy_usb_factory;
+
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+ USBDevice *(*usbdevice_init)(const char *params))
{
- while (info->qdev.name) {
- usb_qdev_register(info);
- info++;
+ if (usbdevice_name) {
+ LegacyUSBFactory *f = g_malloc0(sizeof(*f));
+ f->name = typename;
+ f->usbdevice_name = usbdevice_name;
+ f->usbdevice_init = usbdevice_init;
+ legacy_usb_factory = g_slist_append(legacy_usb_factory, f);
}
}
@@ -143,7 +236,7 @@ USBDevice *usb_create(USBBus *bus, const char *name)
#endif
dev = qdev_create(&bus->qbus, name);
- return DO_UPCAST(USBDevice, qdev, dev);
+ return USB_DEVICE(dev);
}
USBDevice *usb_create_simple(USBBus *bus, const char *name)
@@ -249,7 +342,7 @@ int usb_claim_port(USBDevice *dev)
return -1;
}
} else {
- if (bus->nfree == 1 && strcmp(dev->qdev.info->name, "usb-hub") != 0) {
+ if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {
/* Create a new hub and chain it on */
usb_create_simple(bus, "usb-hub");
}
@@ -364,7 +457,7 @@ static const char *usb_speed(unsigned int speed)
static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
USBBus *bus = usb_bus_from_device(dev);
monitor_printf(mon, "%*saddr %d.%d, port %s, speed %s, name %s%s\n",
@@ -376,13 +469,13 @@ static void usb_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
static char *usb_get_dev_path(DeviceState *qdev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
return g_strdup(dev->port->path);
}
static char *usb_get_fw_dev_path(DeviceState *qdev)
{
- USBDevice *dev = DO_UPCAST(USBDevice, qdev, qdev);
+ USBDevice *dev = USB_DEVICE(qdev);
char *fw_path, *in;
ssize_t pos = 0, fw_len;
long nr;
@@ -433,8 +526,8 @@ void usb_info(Monitor *mon)
USBDevice *usbdevice_create(const char *cmdline)
{
USBBus *bus = usb_bus_find(-1 /* any */);
- DeviceInfo *info;
- USBDeviceInfo *usb;
+ LegacyUSBFactory *f = NULL;
+ GSList *i;
char driver[32];
const char *params;
int len;
@@ -451,17 +544,13 @@ USBDevice *usbdevice_create(const char *cmdline)
pstrcpy(driver, sizeof(driver), cmdline);
}
- for (info = device_info_list; info != NULL; info = info->next) {
- if (info->bus_info != &usb_bus_info)
- continue;
- usb = DO_UPCAST(USBDeviceInfo, qdev, info);
- if (usb->usbdevice_name == NULL)
- continue;
- if (strcmp(usb->usbdevice_name, driver) != 0)
- continue;
- break;
+ for (i = legacy_usb_factory; i; i = i->next) {
+ f = i->data;
+ if (strcmp(f->usbdevice_name, driver) == 0) {
+ break;
+ }
}
- if (info == NULL) {
+ if (i == NULL) {
#if 0
/* no error because some drivers are not converted (yet) */
error_report("usbdevice %s not found", driver);
@@ -469,12 +558,37 @@ USBDevice *usbdevice_create(const char *cmdline)
return NULL;
}
- if (!usb->usbdevice_init) {
+ if (!f->usbdevice_init) {
if (*params) {
error_report("usbdevice %s accepts no params", driver);
return NULL;
}
- return usb_create_simple(bus, usb->qdev.name);
+ return usb_create_simple(bus, f->name);
}
- return usb->usbdevice_init(params);
+ return f->usbdevice_init(params);
+}
+
+static void usb_device_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->bus_info = &usb_bus_info;
+ k->init = usb_qdev_init;
+ k->unplug = qdev_simple_unplug_cb;
+ k->exit = usb_qdev_exit;
}
+
+static TypeInfo usb_device_type_info = {
+ .name = TYPE_USB_DEVICE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(USBDevice),
+ .abstract = true,
+ .class_size = sizeof(USBDeviceClass),
+ .class_init = usb_device_class_init,
+};
+
+static void usb_register_devices(void)
+{
+ type_register_static(&usb_device_type_info);
+}
+
+device_init(usb_register_devices);
diff --git a/hw/usb-ccid.c b/hw/usb-ccid.c
index cd349f3f17..881da3002e 100644
--- a/hw/usb-ccid.c
+++ b/hw/usb-ccid.c
@@ -269,7 +269,6 @@ typedef struct USBCCIDState {
USBDevice dev;
CCIDBus bus;
CCIDCardState *card;
- CCIDCardInfo *cardinfo; /* caching the info pointer */
BulkIn bulk_in_pending[BULK_IN_PENDING_NUM]; /* circular */
uint32_t bulk_in_pending_start;
uint32_t bulk_in_pending_end; /* first free */
@@ -468,6 +467,43 @@ static const USBDesc desc_ccid = {
.str = desc_strings,
};
+static const uint8_t *ccid_card_get_atr(CCIDCardState *card, uint32_t *len)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->get_atr) {
+ return cc->get_atr(card, len);
+ }
+ return NULL;
+}
+
+static void ccid_card_apdu_from_guest(CCIDCardState *card,
+ const uint8_t *apdu,
+ uint32_t len)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->apdu_from_guest) {
+ cc->apdu_from_guest(card, apdu, len);
+ }
+}
+
+static int ccid_card_exitfn(CCIDCardState *card)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->exitfn) {
+ return cc->exitfn(card);
+ }
+ return 0;
+}
+
+static int ccid_card_initfn(CCIDCardState *card)
+{
+ CCIDCardClass *cc = CCID_CARD_GET_CLASS(card);
+ if (cc->initfn) {
+ return cc->initfn(card);
+ }
+ return 0;
+}
+
static bool ccid_has_pending_answers(USBCCIDState *s)
{
return s->pending_answers_num > 0;
@@ -611,14 +647,6 @@ static int ccid_handle_control(USBDevice *dev, USBPacket *p, int request,
}
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
-
/* Class specific requests. */
case InterfaceOutClass | CCID_CONTROL_ABORT:
DPRINTF(s, 1, "ccid_control abort UNIMPLEMENTED\n");
@@ -749,7 +777,7 @@ static void ccid_write_data_block_atr(USBCCIDState *s, CCID_Header *recv)
uint32_t len = 0;
if (s->card) {
- atr = s->cardinfo->get_atr(s->card, &len);
+ atr = ccid_card_get_atr(s->card, &len);
}
ccid_write_data_block(s, recv->bSlot, recv->bSeq, atr, len);
}
@@ -835,7 +863,7 @@ static void ccid_on_apdu_from_guest(USBCCIDState *s, CCID_XferBlock *recv)
recv->hdr.bSeq, len);
ccid_add_pending_answer(s, (CCID_Header *)recv);
if (s->card) {
- s->cardinfo->apdu_from_guest(s->card, recv->abData, len);
+ ccid_card_apdu_from_guest(s->card, recv->abData, len);
} else {
DPRINTF(s, D_WARN, "warning: discarded apdu\n");
}
@@ -1121,26 +1149,21 @@ void ccid_card_card_inserted(CCIDCardState *card)
static int ccid_card_exit(DeviceState *qdev)
{
int ret = 0;
- CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
- CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, qdev->info);
+ CCIDCardState *card = CCID_CARD(qdev);
USBCCIDState *s =
DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
if (ccid_card_inserted(s)) {
ccid_card_card_removed(card);
}
- if (info->exitfn) {
- ret = info->exitfn(card);
- }
+ ret = ccid_card_exitfn(card);
s->card = NULL;
- s->cardinfo = NULL;
return ret;
}
-static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
+static int ccid_card_init(DeviceState *qdev)
{
- CCIDCardState *card = DO_UPCAST(CCIDCardState, qdev, qdev);
- CCIDCardInfo *info = DO_UPCAST(CCIDCardInfo, qdev, base);
+ CCIDCardState *card = CCID_CARD(qdev);
USBCCIDState *s =
DO_UPCAST(USBCCIDState, dev.qdev, card->qdev.parent_bus->parent);
int ret = 0;
@@ -1154,22 +1177,13 @@ static int ccid_card_init(DeviceState *qdev, DeviceInfo *base)
error_report("Warning: usb-ccid card already full, not adding");
return -1;
}
- ret = info->initfn ? info->initfn(card) : ret;
+ ret = ccid_card_initfn(card);
if (ret == 0) {
s->card = card;
- s->cardinfo = info;
}
return ret;
}
-void ccid_card_qdev_register(CCIDCardInfo *card)
-{
- card->qdev.bus_info = &ccid_bus_info;
- card->qdev.init = ccid_card_init;
- card->qdev.exit = ccid_card_exit;
- qdev_register(&card->qdev);
-}
-
static int ccid_initfn(USBDevice *dev)
{
USBCCIDState *s = DO_UPCAST(USBCCIDState, dev, dev);
@@ -1178,7 +1192,6 @@ static int ccid_initfn(USBDevice *dev)
qbus_create_inplace(&s->bus.qbus, &ccid_bus_info, &dev->qdev, NULL);
s->bus.qbus.allow_hotplug = 1;
s->card = NULL;
- s->cardinfo = NULL;
s->migration_state = MIGRATION_NONE;
s->migration_target_ip = 0;
s->migration_target_port = 0;
@@ -1294,28 +1307,57 @@ static VMStateDescription ccid_vmstate = {
}
};
-static struct USBDeviceInfo ccid_info = {
- .product_desc = "QEMU USB CCID",
- .qdev.name = CCID_DEV_NAME,
- .qdev.desc = "CCID Rev 1.1 smartcard reader",
- .qdev.size = sizeof(USBCCIDState),
- .init = ccid_initfn,
- .usb_desc = &desc_ccid,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = ccid_handle_reset,
- .handle_control = ccid_handle_control,
- .handle_data = ccid_handle_data,
- .handle_destroy = ccid_handle_destroy,
- .usbdevice_name = "ccid",
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.vmsd = &ccid_vmstate,
+static Property ccid_properties[] = {
+ DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ccid_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = ccid_initfn;
+ uc->product_desc = "QEMU USB CCID";
+ uc->usb_desc = &desc_ccid;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = ccid_handle_reset;
+ uc->handle_control = ccid_handle_control;
+ uc->handle_data = ccid_handle_data;
+ uc->handle_destroy = ccid_handle_destroy;
+ dc->desc = "CCID Rev 1.1 smartcard reader";
+ dc->vmsd = &ccid_vmstate;
+ dc->props = ccid_properties;
+}
+
+static TypeInfo ccid_info = {
+ .name = CCID_DEV_NAME,
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBCCIDState),
+ .class_init = ccid_class_initfn,
+};
+
+static void ccid_card_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->bus_info = &ccid_bus_info;
+ k->init = ccid_card_init;
+ k->exit = ccid_card_exit;
+}
+
+static TypeInfo ccid_card_type_info = {
+ .name = TYPE_CCID_CARD,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(CCIDCardState),
+ .abstract = true,
+ .class_size = sizeof(CCIDCardClass),
+ .class_init = ccid_card_class_init,
};
static void ccid_register_devices(void)
{
- usb_qdev_register(&ccid_info);
+ type_register_static(&ccid_card_type_info);
+ type_register_static(&ccid_info);
+ usb_legacy_register(CCID_DEV_NAME, "ccid", NULL);
}
device_init(ccid_register_devices)
diff --git a/hw/usb-desc.c b/hw/usb-desc.c
index ae2d384bb3..3c3ed6a802 100644
--- a/hw/usb-desc.c
+++ b/hw/usb-desc.c
@@ -192,9 +192,10 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
{
- uint8_t bLength = 0x07;
+ uint8_t bLength = ep->is_audio ? 0x09 : 0x07;
+ uint8_t extralen = ep->extra ? ep->extra[0] : 0;
- if (len < bLength) {
+ if (len < bLength + extralen) {
return -1;
}
@@ -205,8 +206,15 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len)
dest[0x04] = usb_lo(ep->wMaxPacketSize);
dest[0x05] = usb_hi(ep->wMaxPacketSize);
dest[0x06] = ep->bInterval;
+ if (ep->is_audio) {
+ dest[0x07] = ep->bRefresh;
+ dest[0x08] = ep->bSynchAddress;
+ }
+ if (ep->extra) {
+ memcpy(dest + bLength, ep->extra, extralen);
+ }
- return bLength;
+ return bLength + extralen;
}
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
@@ -223,9 +231,114 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len)
/* ------------------------------------------------------------------ */
+static void usb_desc_ep_init(USBDevice *dev)
+{
+ const USBDescIface *iface;
+ int i, e, pid, ep;
+
+ usb_ep_init(dev);
+ for (i = 0; i < dev->ninterfaces; i++) {
+ iface = dev->ifaces[i];
+ if (iface == NULL) {
+ continue;
+ }
+ for (e = 0; e < iface->bNumEndpoints; e++) {
+ pid = (iface->eps[e].bEndpointAddress & USB_DIR_IN) ?
+ USB_TOKEN_IN : USB_TOKEN_OUT;
+ ep = iface->eps[e].bEndpointAddress & 0x0f;
+ usb_ep_set_type(dev, pid, ep, iface->eps[e].bmAttributes & 0x03);
+ usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber);
+ usb_ep_set_max_packet_size(dev, pid, ep,
+ iface->eps[e].wMaxPacketSize);
+ }
+ }
+}
+
+static const USBDescIface *usb_desc_find_interface(USBDevice *dev,
+ int nif, int alt)
+{
+ const USBDescIface *iface;
+ int g, i;
+
+ if (!dev->config) {
+ return NULL;
+ }
+ for (g = 0; g < dev->config->nif_groups; g++) {
+ for (i = 0; i < dev->config->if_groups[g].nif; i++) {
+ iface = &dev->config->if_groups[g].ifs[i];
+ if (iface->bInterfaceNumber == nif &&
+ iface->bAlternateSetting == alt) {
+ return iface;
+ }
+ }
+ }
+ for (i = 0; i < dev->config->nif; i++) {
+ iface = &dev->config->ifs[i];
+ if (iface->bInterfaceNumber == nif &&
+ iface->bAlternateSetting == alt) {
+ return iface;
+ }
+ }
+ return NULL;
+}
+
+static int usb_desc_set_interface(USBDevice *dev, int index, int value)
+{
+ const USBDescIface *iface;
+ int old;
+
+ iface = usb_desc_find_interface(dev, index, value);
+ if (iface == NULL) {
+ return -1;
+ }
+
+ old = dev->altsetting[index];
+ dev->altsetting[index] = value;
+ dev->ifaces[index] = iface;
+ usb_desc_ep_init(dev);
+
+ if (old != value) {
+ usb_device_set_interface(dev, index, old, value);
+ }
+ return 0;
+}
+
+static int usb_desc_set_config(USBDevice *dev, int value)
+{
+ int i;
+
+ if (value == 0) {
+ dev->configuration = 0;
+ dev->ninterfaces = 0;
+ dev->config = NULL;
+ } else {
+ for (i = 0; i < dev->device->bNumConfigurations; i++) {
+ if (dev->device->confs[i].bConfigurationValue == value) {
+ dev->configuration = value;
+ dev->ninterfaces = dev->device->confs[i].bNumInterfaces;
+ dev->config = dev->device->confs + i;
+ assert(dev->ninterfaces <= USB_MAX_INTERFACES);
+ }
+ }
+ if (i < dev->device->bNumConfigurations) {
+ return -1;
+ }
+ }
+
+ for (i = 0; i < dev->ninterfaces; i++) {
+ usb_desc_set_interface(dev, i, 0);
+ }
+ for (; i < USB_MAX_INTERFACES; i++) {
+ dev->altsetting[i] = 0;
+ dev->ifaces[i] = NULL;
+ }
+
+ return 0;
+}
+
static void usb_desc_setdefaults(USBDevice *dev)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
assert(desc != NULL);
switch (dev->speed) {
@@ -237,12 +350,12 @@ static void usb_desc_setdefaults(USBDevice *dev)
dev->device = desc->high;
break;
}
- dev->config = dev->device->confs;
+ usb_desc_set_config(dev, 0);
}
void usb_desc_init(USBDevice *dev)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
assert(desc != NULL);
dev->speed = USB_SPEED_FULL;
@@ -258,7 +371,7 @@ void usb_desc_init(USBDevice *dev)
void usb_desc_attach(USBDevice *dev)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
assert(desc != NULL);
if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) {
@@ -267,7 +380,7 @@ void usb_desc_attach(USBDevice *dev)
dev->speed = USB_SPEED_FULL;
} else {
fprintf(stderr, "usb: port/device speed mismatch for \"%s\"\n",
- dev->info->product_desc);
+ usb_device_get_product_desc(dev));
return;
}
usb_desc_setdefaults(dev);
@@ -323,7 +436,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
str = usb_desc_get_string(dev, index);
if (str == NULL) {
- str = dev->info->usb_desc->str[index];
+ str = usb_device_get_usb_desc(dev)->str[index];
if (str == NULL) {
return 0;
}
@@ -342,7 +455,7 @@ int usb_desc_string(USBDevice *dev, int index, uint8_t *dest, size_t len)
int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len)
{
- const USBDesc *desc = dev->info->usb_desc;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
const USBDescDevice *other_dev;
uint8_t buf[256];
uint8_t type = value >> 8;
@@ -350,9 +463,9 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
int ret = -1;
if (dev->speed == USB_SPEED_HIGH) {
- other_dev = dev->info->usb_desc->full;
+ other_dev = usb_device_get_usb_desc(dev)->full;
} else {
- other_dev = dev->info->usb_desc->high;
+ other_dev = usb_device_get_usb_desc(dev)->high;
}
switch(type) {
@@ -407,8 +520,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len
int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
int request, int value, int index, int length, uint8_t *data)
{
- const USBDesc *desc = dev->info->usb_desc;
- int i, ret = -1;
+ const USBDesc *desc = usb_device_get_usb_desc(dev);
+ int ret = -1;
assert(desc != NULL);
switch(request) {
@@ -427,12 +540,7 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
ret = 1;
break;
case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
- for (i = 0; i < dev->device->bNumConfigurations; i++) {
- if (dev->device->confs[i].bConfigurationValue == value) {
- dev->config = dev->device->confs + i;
- ret = 0;
- }
- }
+ ret = usb_desc_set_config(dev, value);
trace_usb_set_config(dev->addr, value, ret);
break;
@@ -461,6 +569,19 @@ int usb_desc_handle_control(USBDevice *dev, USBPacket *p,
}
trace_usb_set_device_feature(dev->addr, value, ret);
break;
+
+ case InterfaceRequest | USB_REQ_GET_INTERFACE:
+ if (index < 0 || index >= dev->ninterfaces) {
+ break;
+ }
+ data[0] = dev->altsetting[index];
+ ret = 1;
+ break;
+ case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
+ ret = usb_desc_set_interface(dev, index, value);
+ trace_usb_set_interface(dev->addr, index, value, ret);
+ break;
+
}
return ret;
}
diff --git a/hw/usb-desc.h b/hw/usb-desc.h
index 5c14e4abdc..d6e07ea5d2 100644
--- a/hw/usb-desc.h
+++ b/hw/usb-desc.h
@@ -71,6 +71,11 @@ struct USBDescEndpoint {
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
+ uint8_t bRefresh;
+ uint8_t bSynchAddress;
+
+ uint8_t is_audio; /* has bRefresh + bSynchAddress */
+ uint8_t *extra;
};
struct USBDescOther {
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index 7c926c0d47..75ef71e69e 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -715,7 +715,8 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev)
EHCIQueue *q, *tmp;
QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) {
- if (q->packet.owner != dev) {
+ if (q->packet.owner == NULL ||
+ q->packet.owner->dev != dev) {
continue;
}
ehci_free_queue(q);
@@ -2262,30 +2263,46 @@ static Property ehci_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
-static PCIDeviceInfo ehci_info[] = {
- {
- .qdev.name = "usb-ehci",
- .qdev.size = sizeof(EHCIState),
- .qdev.vmsd = &vmstate_ehci,
- .init = usb_ehci_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801D, /* ich4 */
- .revision = 0x10,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = ehci_properties,
- },{
- .qdev.name = "ich9-usb-ehci1",
- .qdev.size = sizeof(EHCIState),
- .qdev.vmsd = &vmstate_ehci,
- .init = usb_ehci_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = ehci_properties,
- },{
- /* end of list */
- }
+static void ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_properties;
+}
+
+static TypeInfo ehci_info = {
+ .name = "usb-ehci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ehci_class_init,
+};
+
+static void ich9_ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_properties;
+}
+
+static TypeInfo ich9_ehci_info = {
+ .name = "ich9-usb-ehci1",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ich9_ehci_class_init,
};
static int usb_ehci_initfn(PCIDevice *dev)
@@ -2361,7 +2378,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
static void ehci_register(void)
{
- pci_qdev_register_many(ehci_info);
+ type_register_static(&ehci_info);
+ type_register_static(&ich9_ehci_info);
}
device_init(ehci_register);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index a110c74dda..3c4e45da70 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -384,13 +384,6 @@ static int usb_hid_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* hid specific requests */
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
switch (value >> 8) {
@@ -560,53 +553,81 @@ static const VMStateDescription vmstate_usb_kbd = {
}
};
-static struct USBDeviceInfo hid_info[] = {
- {
- .product_desc = "QEMU USB Tablet",
- .qdev.name = "usb-tablet",
- .usbdevice_name = "tablet",
- .qdev.size = sizeof(USBHIDState),
- .qdev.vmsd = &vmstate_usb_ptr,
- .usb_desc = &desc_tablet,
- .init = usb_tablet_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_hid_handle_reset,
- .handle_control = usb_hid_handle_control,
- .handle_data = usb_hid_handle_data,
- .handle_destroy = usb_hid_handle_destroy,
- },{
- .product_desc = "QEMU USB Mouse",
- .qdev.name = "usb-mouse",
- .usbdevice_name = "mouse",
- .qdev.size = sizeof(USBHIDState),
- .qdev.vmsd = &vmstate_usb_ptr,
- .usb_desc = &desc_mouse,
- .init = usb_mouse_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_hid_handle_reset,
- .handle_control = usb_hid_handle_control,
- .handle_data = usb_hid_handle_data,
- .handle_destroy = usb_hid_handle_destroy,
- },{
- .product_desc = "QEMU USB Keyboard",
- .qdev.name = "usb-kbd",
- .usbdevice_name = "keyboard",
- .qdev.size = sizeof(USBHIDState),
- .qdev.vmsd = &vmstate_usb_kbd,
- .usb_desc = &desc_keyboard,
- .init = usb_keyboard_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_hid_handle_reset,
- .handle_control = usb_hid_handle_control,
- .handle_data = usb_hid_handle_data,
- .handle_destroy = usb_hid_handle_destroy,
- },{
- /* end of list */
- }
+static void usb_hid_class_initfn(ObjectClass *klass, void *data)
+{
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_hid_handle_reset;
+ uc->handle_control = usb_hid_handle_control;
+ uc->handle_data = usb_hid_handle_data;
+ uc->handle_destroy = usb_hid_handle_destroy;
+}
+
+static void usb_tablet_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ usb_hid_class_initfn(klass, data);
+ uc->init = usb_tablet_initfn;
+ uc->product_desc = "QEMU USB Tablet";
+ uc->usb_desc = &desc_tablet;
+ dc->vmsd = &vmstate_usb_ptr;
+}
+
+static TypeInfo usb_tablet_info = {
+ .name = "usb-tablet",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHIDState),
+ .class_init = usb_tablet_class_initfn,
+};
+
+static void usb_mouse_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ usb_hid_class_initfn(klass, data);
+ uc->init = usb_mouse_initfn;
+ uc->product_desc = "QEMU USB Mouse";
+ uc->usb_desc = &desc_mouse;
+ dc->vmsd = &vmstate_usb_ptr;
+}
+
+static TypeInfo usb_mouse_info = {
+ .name = "usb-mouse",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHIDState),
+ .class_init = usb_mouse_class_initfn,
+};
+
+static void usb_keyboard_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ usb_hid_class_initfn(klass, data);
+ uc->init = usb_keyboard_initfn;
+ uc->product_desc = "QEMU USB Keyboard";
+ uc->usb_desc = &desc_keyboard;
+ dc->vmsd = &vmstate_usb_kbd;
+}
+
+static TypeInfo usb_keyboard_info = {
+ .name = "usb-kbd",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHIDState),
+ .class_init = usb_keyboard_class_initfn,
};
static void usb_hid_register_devices(void)
{
- usb_qdev_register_many(hid_info);
+ type_register_static(&usb_tablet_info);
+ usb_legacy_register("usb-tablet", "tablet", NULL);
+ type_register_static(&usb_mouse_info);
+ usb_legacy_register("usb-mouse", "mouse", NULL);
+ type_register_static(&usb_keyboard_info);
+ usb_legacy_register("usb-kbd", "keyboard", NULL);
}
device_init(usb_hid_register_devices)
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index e1959372e7..956b020eed 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -258,13 +258,6 @@ static int usb_hub_handle_control(USBDevice *dev, USBPacket *p,
}
ret = 0;
break;
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* usb specific requests */
case GetHubStatus:
data[0] = 0;
@@ -540,23 +533,32 @@ static const VMStateDescription vmstate_usb_hub = {
}
};
-static struct USBDeviceInfo hub_info = {
- .product_desc = "QEMU USB Hub",
- .qdev.name = "usb-hub",
- .qdev.fw_name = "hub",
- .qdev.size = sizeof(USBHubState),
- .qdev.vmsd = &vmstate_usb_hub,
- .usb_desc = &desc_hub,
- .init = usb_hub_initfn,
- .handle_packet = usb_hub_handle_packet,
- .handle_reset = usb_hub_handle_reset,
- .handle_control = usb_hub_handle_control,
- .handle_data = usb_hub_handle_data,
- .handle_destroy = usb_hub_handle_destroy,
+static void usb_hub_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_hub_initfn;
+ uc->product_desc = "QEMU USB Hub";
+ uc->usb_desc = &desc_hub;
+ uc->handle_packet = usb_hub_handle_packet;
+ uc->handle_reset = usb_hub_handle_reset;
+ uc->handle_control = usb_hub_handle_control;
+ uc->handle_data = usb_hub_handle_data;
+ uc->handle_destroy = usb_hub_handle_destroy;
+ dc->fw_name = "hub";
+ dc->vmsd = &vmstate_usb_hub;
+}
+
+static TypeInfo hub_info = {
+ .name = "usb-hub",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHubState),
+ .class_init = usb_hub_class_initfn,
};
static void usb_hub_register_devices(void)
{
- usb_qdev_register(&hub_info);
+ type_register_static(&hub_info);
}
device_init(usb_hub_register_devices)
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index e42729699d..6153376f3f 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -306,19 +306,9 @@ static int usb_msd_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
/* Class specific requests. */
case ClassInterfaceOutRequest | MassStorageReset:
/* Reset state ready for the next CBW. */
@@ -646,32 +636,42 @@ static const VMStateDescription vmstate_usb_msd = {
}
};
-static struct USBDeviceInfo msd_info = {
- .product_desc = "QEMU USB MSD",
- .qdev.name = "usb-storage",
- .qdev.fw_name = "storage",
- .qdev.size = sizeof(MSDState),
- .qdev.vmsd = &vmstate_usb_msd,
- .usb_desc = &desc,
- .init = usb_msd_initfn,
- .handle_packet = usb_generic_handle_packet,
- .cancel_packet = usb_msd_cancel_io,
- .handle_attach = usb_desc_attach,
- .handle_reset = usb_msd_handle_reset,
- .handle_control = usb_msd_handle_control,
- .handle_data = usb_msd_handle_data,
- .usbdevice_name = "disk",
- .usbdevice_init = usb_msd_init,
- .qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(MSDState, conf),
- DEFINE_PROP_STRING("serial", MSDState, serial),
- DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property msd_properties[] = {
+ DEFINE_BLOCK_PROPERTIES(MSDState, conf),
+ DEFINE_PROP_STRING("serial", MSDState, serial),
+ DEFINE_PROP_BIT("removable", MSDState, removable, 0, false),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_msd_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_msd_initfn;
+ uc->product_desc = "QEMU USB MSD";
+ uc->usb_desc = &desc;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->cancel_packet = usb_msd_cancel_io;
+ uc->handle_attach = usb_desc_attach;
+ uc->handle_reset = usb_msd_handle_reset;
+ uc->handle_control = usb_msd_handle_control;
+ uc->handle_data = usb_msd_handle_data;
+ dc->fw_name = "storage";
+ dc->vmsd = &vmstate_usb_msd;
+ dc->props = msd_properties;
+}
+
+static TypeInfo msd_info = {
+ .name = "usb-storage",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(MSDState),
+ .class_init = usb_msd_class_initfn,
};
static void usb_msd_register_devices(void)
{
- usb_qdev_register(&msd_info);
+ type_register_static(&msd_info);
+ usb_legacy_register("usb-storage", "disk", usb_msd_init);
}
device_init(usb_msd_register_devices)
diff --git a/hw/usb-musb.c b/hw/usb-musb.c
index 01e2e7c389..4f528d25e5 100644
--- a/hw/usb-musb.c
+++ b/hw/usb-musb.c
@@ -812,7 +812,8 @@ static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
for (ep = 0; ep < 16; ep++) {
for (dir = 0; dir < 2; dir++) {
- if (s->ep[ep].packey[dir].p.owner != dev) {
+ if (s->ep[ep].packey[dir].p.owner == NULL ||
+ s->ep[ep].packey[dir].p.owner->dev != dev) {
continue;
}
usb_cancel_packet(&s->ep[ep].packey[dir].p);
diff --git a/hw/usb-net.c b/hw/usb-net.c
index f91fa32334..e2111413b4 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -71,9 +71,6 @@ enum usbstring_idx {
#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
-#define USB_DT_CS_INTERFACE 0x24
-#define USB_DT_CS_ENDPOINT 0x25
-
#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
#define USB_CDC_REQ_SET_LINE_CODING 0x20
@@ -1098,17 +1095,6 @@ static int usb_net_handle_control(USBDevice *dev, USBPacket *p,
#endif
break;
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- case InterfaceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
-
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
-
default:
fail:
fprintf(stderr, "usbnet: failed control transaction: "
@@ -1351,7 +1337,7 @@ static int usb_net_initfn(USBDevice *dev)
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_usbnet_info, &s->conf,
- s->dev.qdev.info->name, s->dev.qdev.id, s);
+ object_get_typename(OBJECT(s)), s->dev.qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
snprintf(s->usbstring_mac, sizeof(s->usbstring_mac),
"%02x%02x%02x%02x%02x%02x",
@@ -1399,29 +1385,39 @@ static const VMStateDescription vmstate_usb_net = {
.unmigratable = 1,
};
-static struct USBDeviceInfo net_info = {
- .product_desc = "QEMU USB Network Interface",
- .qdev.name = "usb-net",
- .qdev.fw_name = "network",
- .qdev.size = sizeof(USBNetState),
- .qdev.vmsd = &vmstate_usb_net,
- .usb_desc = &desc_net,
- .init = usb_net_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_net_handle_reset,
- .handle_control = usb_net_handle_control,
- .handle_data = usb_net_handle_data,
- .handle_destroy = usb_net_handle_destroy,
- .usbdevice_name = "net",
- .usbdevice_init = usb_net_init,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(USBNetState, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property net_properties[] = {
+ DEFINE_NIC_PROPERTIES(USBNetState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_net_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_net_initfn;
+ uc->product_desc = "QEMU USB Network Interface";
+ uc->usb_desc = &desc_net;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_net_handle_reset;
+ uc->handle_control = usb_net_handle_control;
+ uc->handle_data = usb_net_handle_data;
+ uc->handle_destroy = usb_net_handle_destroy;
+ dc->fw_name = "network";
+ dc->vmsd = &vmstate_usb_net;
+ dc->props = net_properties;
+}
+
+static TypeInfo net_info = {
+ .name = "usb-net",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBNetState),
+ .class_init = usb_net_class_initfn,
};
static void usb_net_register_devices(void)
{
- usb_qdev_register(&net_info);
+ type_register_static(&net_info);
+ usb_legacy_register("usb-net", "net", usb_net_init);
}
device_init(usb_net_register_devices)
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 81488c48e2..425030f141 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1707,7 +1707,9 @@ static void ohci_mem_write(void *opaque,
static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev)
{
- if (ohci->async_td && ohci->usb_packet.owner == dev) {
+ if (ohci->async_td &&
+ ohci->usb_packet.owner != NULL &&
+ ohci->usb_packet.owner->dev == dev) {
usb_cancel_packet(&ohci->usb_packet);
ohci->async_td = 0;
}
@@ -1775,7 +1777,7 @@ static int usb_ohci_init(OHCIState *ohci, DeviceState *dev,
memory_region_init_io(&ohci->mem, &ohci_mem_ops, ohci, "ohci", 256);
ohci->localmem_base = localmem_base;
- ohci->name = dev->info->name;
+ ohci->name = object_get_typename(OBJECT(dev));
usb_packet_init(&ohci->usb_packet);
ohci->async_td = 0;
@@ -1834,37 +1836,59 @@ static int ohci_init_pxa(SysBusDevice *dev)
return 0;
}
-static PCIDeviceInfo ohci_pci_info = {
- .qdev.name = "pci-ohci",
- .qdev.desc = "Apple USB Controller",
- .qdev.size = sizeof(OHCIPCIState),
- .init = usb_ohci_initfn_pci,
- .vendor_id = PCI_VENDOR_ID_APPLE,
- .device_id = PCI_DEVICE_ID_APPLE_IPID_USB,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = (Property[]) {
- DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
- DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
- DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property ohci_pci_properties[] = {
+ DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
+ DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
+ DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
+ DEFINE_PROP_END_OF_LIST(),
};
-static SysBusDeviceInfo ohci_sysbus_info = {
- .init = ohci_init_pxa,
- .qdev.name = "sysbus-ohci",
- .qdev.desc = "OHCI USB Controller",
- .qdev.size = sizeof(OHCISysBusState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
- DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3),
- DEFINE_PROP_END_OF_LIST(),
- }
+static void ohci_pci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ohci_initfn_pci;
+ k->vendor_id = PCI_VENDOR_ID_APPLE;
+ k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->desc = "Apple USB Controller";
+ dc->props = ohci_pci_properties;
+}
+
+static TypeInfo ohci_pci_info = {
+ .name = "pci-ohci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(OHCIPCIState),
+ .class_init = ohci_pci_class_init,
+};
+
+static Property ohci_sysbus_properties[] = {
+ DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
+ DEFINE_PROP_TADDR("dma-offset", OHCISysBusState, dma_offset, 3),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void ohci_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sbc->init = ohci_init_pxa;
+ dc->desc = "OHCI USB Controller";
+ dc->props = ohci_sysbus_properties;
+}
+
+static TypeInfo ohci_sysbus_info = {
+ .name = "sysbus-ohci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(OHCISysBusState),
+ .class_init = ohci_sysbus_class_init,
};
static void ohci_register(void)
{
- pci_qdev_register(&ohci_pci_info);
- sysbus_register_withprop(&ohci_sysbus_info);
+ type_register_static(&ohci_pci_info);
+ type_register_static(&ohci_sysbus_info);
}
device_init(ohci_register);
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 7dbf6dfc6d..c2cb6d24e8 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -233,13 +233,6 @@ static int usb_serial_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case InterfaceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
ret = 0;
break;
@@ -577,49 +570,69 @@ static const VMStateDescription vmstate_usb_serial = {
.unmigratable = 1,
};
-static struct USBDeviceInfo serial_info = {
- .product_desc = "QEMU USB Serial",
- .qdev.name = "usb-serial",
- .qdev.size = sizeof(USBSerialState),
- .qdev.vmsd = &vmstate_usb_serial,
- .usb_desc = &desc_serial,
- .init = usb_serial_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_serial_handle_reset,
- .handle_control = usb_serial_handle_control,
- .handle_data = usb_serial_handle_data,
- .handle_destroy = usb_serial_handle_destroy,
- .usbdevice_name = "serial",
- .usbdevice_init = usb_serial_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property serial_properties[] = {
+ DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+ DEFINE_PROP_END_OF_LIST(),
};
-static struct USBDeviceInfo braille_info = {
- .product_desc = "QEMU USB Braille",
- .qdev.name = "usb-braille",
- .qdev.size = sizeof(USBSerialState),
- .qdev.vmsd = &vmstate_usb_serial,
- .usb_desc = &desc_braille,
- .init = usb_serial_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_serial_handle_reset,
- .handle_control = usb_serial_handle_control,
- .handle_data = usb_serial_handle_data,
- .handle_destroy = usb_serial_handle_destroy,
- .usbdevice_name = "braille",
- .usbdevice_init = usb_braille_init,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBSerialState, cs),
- DEFINE_PROP_END_OF_LIST(),
- },
+static void usb_serial_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_serial_initfn;
+ uc->product_desc = "QEMU USB Serial";
+ uc->usb_desc = &desc_serial;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_serial_handle_reset;
+ uc->handle_control = usb_serial_handle_control;
+ uc->handle_data = usb_serial_handle_data;
+ uc->handle_destroy = usb_serial_handle_destroy;
+ dc->vmsd = &vmstate_usb_serial;
+ dc->props = serial_properties;
+}
+
+static TypeInfo serial_info = {
+ .name = "usb-serial",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBSerialState),
+ .class_init = usb_serial_class_initfn,
+};
+
+static Property braille_properties[] = {
+ DEFINE_PROP_CHR("chardev", USBSerialState, cs),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_braille_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_serial_initfn;
+ uc->product_desc = "QEMU USB Braille";
+ uc->usb_desc = &desc_braille;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_serial_handle_reset;
+ uc->handle_control = usb_serial_handle_control;
+ uc->handle_data = usb_serial_handle_data;
+ uc->handle_destroy = usb_serial_handle_destroy;
+ dc->vmsd = &vmstate_usb_serial;
+ dc->props = braille_properties;
+}
+
+static TypeInfo braille_info = {
+ .name = "usb-braille",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBSerialState),
+ .class_init = usb_braille_class_initfn,
};
static void usb_serial_register_devices(void)
{
- usb_qdev_register(&serial_info);
- usb_qdev_register(&braille_info);
+ type_register_static(&serial_info);
+ usb_legacy_register("usb-serial", "serial", usb_serial_init);
+ type_register_static(&braille_info);
+ usb_legacy_register("usb-braille", "braille", usb_braille_init);
}
device_init(usb_serial_register_devices)
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index f8912e2b0b..cddcc8927a 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -245,7 +245,8 @@ static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev)
UHCIAsync *curr, *n;
QTAILQ_FOREACH_SAFE(curr, &s->async_pending, next, n) {
- if (curr->packet.owner != dev) {
+ if (curr->packet.owner == NULL ||
+ curr->packet.owner->dev != dev) {
continue;
}
uhci_async_unlink(s, curr);
@@ -1191,78 +1192,143 @@ static Property uhci_properties[] = {
DEFINE_PROP_END_OF_LIST(),
};
-static PCIDeviceInfo uhci_info[] = {
- {
- .qdev.name = "piix3-usb-uhci",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .exit = usb_uhci_exit,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371SB_2,
- .revision = 0x01,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "piix4-usb-uhci",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .exit = usb_uhci_exit,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82371AB_2,
- .revision = 0x01,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "vt82c686b-usb-uhci",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_vt82c686b_initfn,
- .exit = usb_uhci_exit,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_UHCI,
- .revision = 0x01,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "ich9-usb-uhci1",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "ich9-usb-uhci2",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- .qdev.name = "ich9-usb-uhci3",
- .qdev.size = sizeof(UHCIState),
- .qdev.vmsd = &vmstate_uhci,
- .init = usb_uhci_common_initfn,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3,
- .revision = 0x03,
- .class_id = PCI_CLASS_SERIAL_USB,
- .qdev.props = uhci_properties,
- },{
- /* end of list */
- }
+static void piix3_uhci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->exit = usb_uhci_exit;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371SB_2;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo piix3_uhci_info = {
+ .name = "piix3-usb-uhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = piix3_uhci_class_init,
+};
+
+static void piix4_uhci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->exit = usb_uhci_exit;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82371AB_2;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo piix4_uhci_info = {
+ .name = "piix4-usb-uhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = piix4_uhci_class_init,
+};
+
+static void vt82c686b_uhci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_vt82c686b_initfn;
+ k->exit = usb_uhci_exit;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_UHCI;
+ k->revision = 0x01;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo vt82c686b_uhci_info = {
+ .name = "vt82c686b-usb-uhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = vt82c686b_uhci_class_init,
+};
+
+static void ich9_uhci1_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI1;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci1_info = {
+ .name = "ich9-usb-uhci1",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = ich9_uhci1_class_init,
+};
+
+static void ich9_uhci2_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI2;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci2_info = {
+ .name = "ich9-usb-uhci2",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = ich9_uhci2_class_init,
+};
+
+static void ich9_uhci3_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_uhci_common_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_UHCI3;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_uhci;
+ dc->props = uhci_properties;
+}
+
+static TypeInfo ich9_uhci3_info = {
+ .name = "ich9-usb-uhci3",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(UHCIState),
+ .class_init = ich9_uhci3_class_init,
};
static void uhci_register(void)
{
- pci_qdev_register_many(uhci_info);
+ type_register_static(&piix3_uhci_info);
+ type_register_static(&piix4_uhci_info);
+ type_register_static(&vt82c686b_uhci_info);
+ type_register_static(&ich9_uhci1_info);
+ type_register_static(&ich9_uhci2_info);
+ type_register_static(&ich9_uhci3_info);
}
device_init(uhci_register);
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
index 25580067f2..14de14d5f7 100644
--- a/hw/usb-wacom.c
+++ b/hw/usb-wacom.c
@@ -263,13 +263,6 @@ static int usb_wacom_handle_control(USBDevice *dev, USBPacket *p,
ret = 0;
switch (request) {
- case DeviceRequest | USB_REQ_GET_INTERFACE:
- data[0] = 0;
- ret = 1;
- break;
- case DeviceOutRequest | USB_REQ_SET_INTERFACE:
- ret = 0;
- break;
case WACOM_SET_REPORT:
if (s->mouse_grabbed) {
qemu_remove_mouse_event_handler(s->eh_entry);
@@ -356,24 +349,33 @@ static const VMStateDescription vmstate_usb_wacom = {
.unmigratable = 1,
};
-static struct USBDeviceInfo wacom_info = {
- .product_desc = "QEMU PenPartner Tablet",
- .qdev.name = "usb-wacom-tablet",
- .qdev.desc = "QEMU PenPartner Tablet",
- .usbdevice_name = "wacom-tablet",
- .usb_desc = &desc_wacom,
- .qdev.size = sizeof(USBWacomState),
- .qdev.vmsd = &vmstate_usb_wacom,
- .init = usb_wacom_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_wacom_handle_reset,
- .handle_control = usb_wacom_handle_control,
- .handle_data = usb_wacom_handle_data,
- .handle_destroy = usb_wacom_handle_destroy,
+static void usb_wacom_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->product_desc = "QEMU PenPartner Tablet";
+ uc->usb_desc = &desc_wacom;
+ uc->init = usb_wacom_initfn;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_wacom_handle_reset;
+ uc->handle_control = usb_wacom_handle_control;
+ uc->handle_data = usb_wacom_handle_data;
+ uc->handle_destroy = usb_wacom_handle_destroy;
+ dc->desc = "QEMU PenPartner Tablet";
+ dc->vmsd = &vmstate_usb_wacom;
+}
+
+static TypeInfo wacom_info = {
+ .name = "usb-wacom-tablet",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBWacomState),
+ .class_init = usb_wacom_class_init,
};
static void usb_wacom_register_devices(void)
{
- usb_qdev_register(&wacom_info);
+ type_register_static(&wacom_info);
+ usb_legacy_register("usb-wacom-tablet", "wacom-tablet", NULL);
}
device_init(usb_wacom_register_devices)
diff --git a/hw/usb-xhci.c b/hw/usb-xhci.c
new file mode 100644
index 0000000000..37e887c431
--- /dev/null
+++ b/hw/usb-xhci.c
@@ -0,0 +1,2759 @@
+/*
+ * USB xHCI controller emulation
+ *
+ * Copyright (c) 2011 Securiforest
+ * Date: 2011-05-11 ; Author: Hector Martin <hector@marcansoft.com>
+ * Based on usb-ohci.c, emulates Renesas NEC USB 3.0
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "qemu-timer.h"
+#include "usb.h"
+#include "pci.h"
+#include "qdev-addr.h"
+#include "msi.h"
+
+//#define DEBUG_XHCI
+//#define DEBUG_DATA
+
+#ifdef DEBUG_XHCI
+#define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DPRINTF(...) do {} while (0)
+#endif
+#define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \
+ __func__, __LINE__); abort(); } while (0)
+
+#define MAXSLOTS 8
+#define MAXINTRS 1
+
+#define USB2_PORTS 4
+#define USB3_PORTS 4
+
+#define MAXPORTS (USB2_PORTS+USB3_PORTS)
+
+#define TD_QUEUE 24
+#define BG_XFERS 8
+#define BG_PKTS 8
+
+/* Very pessimistic, let's hope it's enough for all cases */
+#define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS)
+/* Do not deliver ER Full events. NEC's driver does some things not bound
+ * to the specs when it gets them */
+#define ER_FULL_HACK
+
+#define LEN_CAP 0x40
+#define OFF_OPER LEN_CAP
+#define LEN_OPER (0x400 + 0x10 * MAXPORTS)
+#define OFF_RUNTIME ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f)
+#define LEN_RUNTIME (0x20 + MAXINTRS * 0x20)
+#define OFF_DOORBELL (OFF_RUNTIME + LEN_RUNTIME)
+#define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20)
+
+/* must be power of 2 */
+#define LEN_REGS 0x2000
+
+#if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS
+# error Increase LEN_REGS
+#endif
+
+#if MAXINTRS > 1
+# error TODO: only one interrupter supported
+#endif
+
+/* bit definitions */
+#define USBCMD_RS (1<<0)
+#define USBCMD_HCRST (1<<1)
+#define USBCMD_INTE (1<<2)
+#define USBCMD_HSEE (1<<3)
+#define USBCMD_LHCRST (1<<7)
+#define USBCMD_CSS (1<<8)
+#define USBCMD_CRS (1<<9)
+#define USBCMD_EWE (1<<10)
+#define USBCMD_EU3S (1<<11)
+
+#define USBSTS_HCH (1<<0)
+#define USBSTS_HSE (1<<2)
+#define USBSTS_EINT (1<<3)
+#define USBSTS_PCD (1<<4)
+#define USBSTS_SSS (1<<8)
+#define USBSTS_RSS (1<<9)
+#define USBSTS_SRE (1<<10)
+#define USBSTS_CNR (1<<11)
+#define USBSTS_HCE (1<<12)
+
+
+#define PORTSC_CCS (1<<0)
+#define PORTSC_PED (1<<1)
+#define PORTSC_OCA (1<<3)
+#define PORTSC_PR (1<<4)
+#define PORTSC_PLS_SHIFT 5
+#define PORTSC_PLS_MASK 0xf
+#define PORTSC_PP (1<<9)
+#define PORTSC_SPEED_SHIFT 10
+#define PORTSC_SPEED_MASK 0xf
+#define PORTSC_SPEED_FULL (1<<10)
+#define PORTSC_SPEED_LOW (2<<10)
+#define PORTSC_SPEED_HIGH (3<<10)
+#define PORTSC_SPEED_SUPER (4<<10)
+#define PORTSC_PIC_SHIFT 14
+#define PORTSC_PIC_MASK 0x3
+#define PORTSC_LWS (1<<16)
+#define PORTSC_CSC (1<<17)
+#define PORTSC_PEC (1<<18)
+#define PORTSC_WRC (1<<19)
+#define PORTSC_OCC (1<<20)
+#define PORTSC_PRC (1<<21)
+#define PORTSC_PLC (1<<22)
+#define PORTSC_CEC (1<<23)
+#define PORTSC_CAS (1<<24)
+#define PORTSC_WCE (1<<25)
+#define PORTSC_WDE (1<<26)
+#define PORTSC_WOE (1<<27)
+#define PORTSC_DR (1<<30)
+#define PORTSC_WPR (1<<31)
+
+#define CRCR_RCS (1<<0)
+#define CRCR_CS (1<<1)
+#define CRCR_CA (1<<2)
+#define CRCR_CRR (1<<3)
+
+#define IMAN_IP (1<<0)
+#define IMAN_IE (1<<1)
+
+#define ERDP_EHB (1<<3)
+
+#define TRB_SIZE 16
+typedef struct XHCITRB {
+ uint64_t parameter;
+ uint32_t status;
+ uint32_t control;
+ target_phys_addr_t addr;
+ bool ccs;
+} XHCITRB;
+
+
+typedef enum TRBType {
+ TRB_RESERVED = 0,
+ TR_NORMAL,
+ TR_SETUP,
+ TR_DATA,
+ TR_STATUS,
+ TR_ISOCH,
+ TR_LINK,
+ TR_EVDATA,
+ TR_NOOP,
+ CR_ENABLE_SLOT,
+ CR_DISABLE_SLOT,
+ CR_ADDRESS_DEVICE,
+ CR_CONFIGURE_ENDPOINT,
+ CR_EVALUATE_CONTEXT,
+ CR_RESET_ENDPOINT,
+ CR_STOP_ENDPOINT,
+ CR_SET_TR_DEQUEUE,
+ CR_RESET_DEVICE,
+ CR_FORCE_EVENT,
+ CR_NEGOTIATE_BW,
+ CR_SET_LATENCY_TOLERANCE,
+ CR_GET_PORT_BANDWIDTH,
+ CR_FORCE_HEADER,
+ CR_NOOP,
+ ER_TRANSFER = 32,
+ ER_COMMAND_COMPLETE,
+ ER_PORT_STATUS_CHANGE,
+ ER_BANDWIDTH_REQUEST,
+ ER_DOORBELL,
+ ER_HOST_CONTROLLER,
+ ER_DEVICE_NOTIFICATION,
+ ER_MFINDEX_WRAP,
+ /* vendor specific bits */
+ CR_VENDOR_VIA_CHALLENGE_RESPONSE = 48,
+ CR_VENDOR_NEC_FIRMWARE_REVISION = 49,
+ CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50,
+} TRBType;
+
+#define CR_LINK TR_LINK
+
+typedef enum TRBCCode {
+ CC_INVALID = 0,
+ CC_SUCCESS,
+ CC_DATA_BUFFER_ERROR,
+ CC_BABBLE_DETECTED,
+ CC_USB_TRANSACTION_ERROR,
+ CC_TRB_ERROR,
+ CC_STALL_ERROR,
+ CC_RESOURCE_ERROR,
+ CC_BANDWIDTH_ERROR,
+ CC_NO_SLOTS_ERROR,
+ CC_INVALID_STREAM_TYPE_ERROR,
+ CC_SLOT_NOT_ENABLED_ERROR,
+ CC_EP_NOT_ENABLED_ERROR,
+ CC_SHORT_PACKET,
+ CC_RING_UNDERRUN,
+ CC_RING_OVERRUN,
+ CC_VF_ER_FULL,
+ CC_PARAMETER_ERROR,
+ CC_BANDWIDTH_OVERRUN,
+ CC_CONTEXT_STATE_ERROR,
+ CC_NO_PING_RESPONSE_ERROR,
+ CC_EVENT_RING_FULL_ERROR,
+ CC_INCOMPATIBLE_DEVICE_ERROR,
+ CC_MISSED_SERVICE_ERROR,
+ CC_COMMAND_RING_STOPPED,
+ CC_COMMAND_ABORTED,
+ CC_STOPPED,
+ CC_STOPPED_LENGTH_INVALID,
+ CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
+ CC_ISOCH_BUFFER_OVERRUN = 31,
+ CC_EVENT_LOST_ERROR,
+ CC_UNDEFINED_ERROR,
+ CC_INVALID_STREAM_ID_ERROR,
+ CC_SECONDARY_BANDWIDTH_ERROR,
+ CC_SPLIT_TRANSACTION_ERROR
+} TRBCCode;
+
+#define TRB_C (1<<0)
+#define TRB_TYPE_SHIFT 10
+#define TRB_TYPE_MASK 0x3f
+#define TRB_TYPE(t) (((t).control >> TRB_TYPE_SHIFT) & TRB_TYPE_MASK)
+
+#define TRB_EV_ED (1<<2)
+
+#define TRB_TR_ENT (1<<1)
+#define TRB_TR_ISP (1<<2)
+#define TRB_TR_NS (1<<3)
+#define TRB_TR_CH (1<<4)
+#define TRB_TR_IOC (1<<5)
+#define TRB_TR_IDT (1<<6)
+#define TRB_TR_TBC_SHIFT 7
+#define TRB_TR_TBC_MASK 0x3
+#define TRB_TR_BEI (1<<9)
+#define TRB_TR_TLBPC_SHIFT 16
+#define TRB_TR_TLBPC_MASK 0xf
+#define TRB_TR_FRAMEID_SHIFT 20
+#define TRB_TR_FRAMEID_MASK 0x7ff
+#define TRB_TR_SIA (1<<31)
+
+#define TRB_TR_DIR (1<<16)
+
+#define TRB_CR_SLOTID_SHIFT 24
+#define TRB_CR_SLOTID_MASK 0xff
+#define TRB_CR_EPID_SHIFT 16
+#define TRB_CR_EPID_MASK 0x1f
+
+#define TRB_CR_BSR (1<<9)
+#define TRB_CR_DC (1<<9)
+
+#define TRB_LK_TC (1<<1)
+
+#define EP_TYPE_MASK 0x7
+#define EP_TYPE_SHIFT 3
+
+#define EP_STATE_MASK 0x7
+#define EP_DISABLED (0<<0)
+#define EP_RUNNING (1<<0)
+#define EP_HALTED (2<<0)
+#define EP_STOPPED (3<<0)
+#define EP_ERROR (4<<0)
+
+#define SLOT_STATE_MASK 0x1f
+#define SLOT_STATE_SHIFT 27
+#define SLOT_STATE(s) (((s)>>SLOT_STATE_SHIFT)&SLOT_STATE_MASK)
+#define SLOT_ENABLED 0
+#define SLOT_DEFAULT 1
+#define SLOT_ADDRESSED 2
+#define SLOT_CONFIGURED 3
+
+#define SLOT_CONTEXT_ENTRIES_MASK 0x1f
+#define SLOT_CONTEXT_ENTRIES_SHIFT 27
+
+typedef enum EPType {
+ ET_INVALID = 0,
+ ET_ISO_OUT,
+ ET_BULK_OUT,
+ ET_INTR_OUT,
+ ET_CONTROL,
+ ET_ISO_IN,
+ ET_BULK_IN,
+ ET_INTR_IN,
+} EPType;
+
+typedef struct XHCIRing {
+ target_phys_addr_t base;
+ target_phys_addr_t dequeue;
+ bool ccs;
+} XHCIRing;
+
+typedef struct XHCIPort {
+ USBPort port;
+ uint32_t portsc;
+} XHCIPort;
+
+struct XHCIState;
+typedef struct XHCIState XHCIState;
+
+typedef struct XHCITransfer {
+ XHCIState *xhci;
+ USBPacket packet;
+ bool running;
+ bool cancelled;
+ bool complete;
+ bool backgrounded;
+ unsigned int iso_pkts;
+ unsigned int slotid;
+ unsigned int epid;
+ bool in_xfer;
+ bool iso_xfer;
+ bool bg_xfer;
+
+ unsigned int trb_count;
+ unsigned int trb_alloced;
+ XHCITRB *trbs;
+
+ unsigned int data_length;
+ unsigned int data_alloced;
+ uint8_t *data;
+
+ TRBCCode status;
+
+ unsigned int pkts;
+ unsigned int pktsize;
+ unsigned int cur_pkt;
+} XHCITransfer;
+
+typedef struct XHCIEPContext {
+ XHCIRing ring;
+ unsigned int next_xfer;
+ unsigned int comp_xfer;
+ XHCITransfer transfers[TD_QUEUE];
+ bool bg_running;
+ bool bg_updating;
+ unsigned int next_bg;
+ XHCITransfer bg_transfers[BG_XFERS];
+ EPType type;
+ target_phys_addr_t pctx;
+ unsigned int max_psize;
+ bool has_bg;
+ uint32_t state;
+} XHCIEPContext;
+
+typedef struct XHCISlot {
+ bool enabled;
+ target_phys_addr_t ctx;
+ unsigned int port;
+ unsigned int devaddr;
+ XHCIEPContext * eps[31];
+} XHCISlot;
+
+typedef struct XHCIEvent {
+ TRBType type;
+ TRBCCode ccode;
+ uint64_t ptr;
+ uint32_t length;
+ uint32_t flags;
+ uint8_t slotid;
+ uint8_t epid;
+} XHCIEvent;
+
+struct XHCIState {
+ PCIDevice pci_dev;
+ USBBus bus;
+ qemu_irq irq;
+ MemoryRegion mem;
+ const char *name;
+ uint32_t msi;
+ unsigned int devaddr;
+
+ /* Operational Registers */
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ uint32_t dnctrl;
+ uint32_t crcr_low;
+ uint32_t crcr_high;
+ uint32_t dcbaap_low;
+ uint32_t dcbaap_high;
+ uint32_t config;
+
+ XHCIPort ports[MAXPORTS];
+ XHCISlot slots[MAXSLOTS];
+
+ /* Runtime Registers */
+ uint32_t mfindex;
+ /* note: we only support one interrupter */
+ uint32_t iman;
+ uint32_t imod;
+ uint32_t erstsz;
+ uint32_t erstba_low;
+ uint32_t erstba_high;
+ uint32_t erdp_low;
+ uint32_t erdp_high;
+
+ target_phys_addr_t er_start;
+ uint32_t er_size;
+ bool er_pcs;
+ unsigned int er_ep_idx;
+ bool er_full;
+
+ XHCIEvent ev_buffer[EV_QUEUE];
+ unsigned int ev_buffer_put;
+ unsigned int ev_buffer_get;
+
+ XHCIRing cmd_ring;
+};
+
+typedef struct XHCIEvRingSeg {
+ uint32_t addr_low;
+ uint32_t addr_high;
+ uint32_t size;
+ uint32_t rsvd;
+} XHCIEvRingSeg;
+
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid);
+
+static inline target_phys_addr_t xhci_addr64(uint32_t low, uint32_t high)
+{
+#if TARGET_PHYS_ADDR_BITS > 32
+ return low | ((target_phys_addr_t)high << 32);
+#else
+ return low;
+#endif
+}
+
+static inline target_phys_addr_t xhci_mask64(uint64_t addr)
+{
+#if TARGET_PHYS_ADDR_BITS > 32
+ return addr;
+#else
+ return addr & 0xffffffff;
+#endif
+}
+
+static void xhci_irq_update(XHCIState *xhci)
+{
+ int level = 0;
+
+ if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE &&
+ xhci->usbcmd && USBCMD_INTE) {
+ level = 1;
+ }
+
+ DPRINTF("xhci_irq_update(): %d\n", level);
+
+ if (xhci->msi && msi_enabled(&xhci->pci_dev)) {
+ if (level) {
+ DPRINTF("xhci_irq_update(): MSI signal\n");
+ msi_notify(&xhci->pci_dev, 0);
+ }
+ } else {
+ qemu_set_irq(xhci->irq, level);
+ }
+}
+
+static inline int xhci_running(XHCIState *xhci)
+{
+ return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full;
+}
+
+static void xhci_die(XHCIState *xhci)
+{
+ xhci->usbsts |= USBSTS_HCE;
+ fprintf(stderr, "xhci: asserted controller error\n");
+}
+
+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
+{
+ XHCITRB ev_trb;
+ target_phys_addr_t addr;
+
+ ev_trb.parameter = cpu_to_le64(event->ptr);
+ ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24));
+ ev_trb.control = (event->slotid << 24) | (event->epid << 16) |
+ event->flags | (event->type << TRB_TYPE_SHIFT);
+ if (xhci->er_pcs) {
+ ev_trb.control |= TRB_C;
+ }
+ ev_trb.control = cpu_to_le32(ev_trb.control);
+
+ DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x\n",
+ xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control);
+
+ addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
+ cpu_physical_memory_write(addr, (uint8_t *) &ev_trb, TRB_SIZE);
+
+ xhci->er_ep_idx++;
+ if (xhci->er_ep_idx >= xhci->er_size) {
+ xhci->er_ep_idx = 0;
+ xhci->er_pcs = !xhci->er_pcs;
+ }
+}
+
+static void xhci_events_update(XHCIState *xhci)
+{
+ target_phys_addr_t erdp;
+ unsigned int dp_idx;
+ bool do_irq = 0;
+
+ if (xhci->usbsts & USBSTS_HCH) {
+ return;
+ }
+
+ erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
+ if (erdp < xhci->er_start ||
+ erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
+ fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
+ fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+ xhci->er_start, xhci->er_size);
+ xhci_die(xhci);
+ return;
+ }
+ dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
+ assert(dp_idx < xhci->er_size);
+
+ /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
+ * deadlocks when the ER is full. Hack it by holding off events until
+ * the driver decides to free at least half of the ring */
+ if (xhci->er_full) {
+ int er_free = dp_idx - xhci->er_ep_idx;
+ if (er_free <= 0) {
+ er_free += xhci->er_size;
+ }
+ if (er_free < (xhci->er_size/2)) {
+ DPRINTF("xhci_events_update(): event ring still "
+ "more than half full (hack)\n");
+ return;
+ }
+ }
+
+ while (xhci->ev_buffer_put != xhci->ev_buffer_get) {
+ assert(xhci->er_full);
+ if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) {
+ DPRINTF("xhci_events_update(): event ring full again\n");
+#ifndef ER_FULL_HACK
+ XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
+ xhci_write_event(xhci, &full);
+#endif
+ do_irq = 1;
+ break;
+ }
+ XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get];
+ xhci_write_event(xhci, event);
+ xhci->ev_buffer_get++;
+ do_irq = 1;
+ if (xhci->ev_buffer_get == EV_QUEUE) {
+ xhci->ev_buffer_get = 0;
+ }
+ }
+
+ if (do_irq) {
+ xhci->erdp_low |= ERDP_EHB;
+ xhci->iman |= IMAN_IP;
+ xhci->usbsts |= USBSTS_EINT;
+ xhci_irq_update(xhci);
+ }
+
+ if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) {
+ DPRINTF("xhci_events_update(): event ring no longer full\n");
+ xhci->er_full = 0;
+ }
+ return;
+}
+
+static void xhci_event(XHCIState *xhci, XHCIEvent *event)
+{
+ target_phys_addr_t erdp;
+ unsigned int dp_idx;
+
+ if (xhci->er_full) {
+ DPRINTF("xhci_event(): ER full, queueing\n");
+ if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
+ fprintf(stderr, "xhci: event queue full, dropping event!\n");
+ return;
+ }
+ xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
+ if (xhci->ev_buffer_put == EV_QUEUE) {
+ xhci->ev_buffer_put = 0;
+ }
+ return;
+ }
+
+ erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high);
+ if (erdp < xhci->er_start ||
+ erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) {
+ fprintf(stderr, "xhci: ERDP out of bounds: "TARGET_FMT_plx"\n", erdp);
+ fprintf(stderr, "xhci: ER at "TARGET_FMT_plx" len %d\n",
+ xhci->er_start, xhci->er_size);
+ xhci_die(xhci);
+ return;
+ }
+
+ dp_idx = (erdp - xhci->er_start) / TRB_SIZE;
+ assert(dp_idx < xhci->er_size);
+
+ if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) {
+ DPRINTF("xhci_event(): ER full, queueing\n");
+#ifndef ER_FULL_HACK
+ XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
+ xhci_write_event(xhci, &full);
+#endif
+ xhci->er_full = 1;
+ if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) {
+ fprintf(stderr, "xhci: event queue full, dropping event!\n");
+ return;
+ }
+ xhci->ev_buffer[xhci->ev_buffer_put++] = *event;
+ if (xhci->ev_buffer_put == EV_QUEUE) {
+ xhci->ev_buffer_put = 0;
+ }
+ } else {
+ xhci_write_event(xhci, event);
+ }
+
+ xhci->erdp_low |= ERDP_EHB;
+ xhci->iman |= IMAN_IP;
+ xhci->usbsts |= USBSTS_EINT;
+
+ xhci_irq_update(xhci);
+}
+
+static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring,
+ target_phys_addr_t base)
+{
+ ring->base = base;
+ ring->dequeue = base;
+ ring->ccs = 1;
+}
+
+static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
+ target_phys_addr_t *addr)
+{
+ while (1) {
+ TRBType type;
+ cpu_physical_memory_read(ring->dequeue, (uint8_t *) trb, TRB_SIZE);
+ trb->addr = ring->dequeue;
+ trb->ccs = ring->ccs;
+ le64_to_cpus(&trb->parameter);
+ le32_to_cpus(&trb->status);
+ le32_to_cpus(&trb->control);
+
+ DPRINTF("xhci: TRB fetched [" TARGET_FMT_plx "]: "
+ "%016" PRIx64 " %08x %08x\n",
+ ring->dequeue, trb->parameter, trb->status, trb->control);
+
+ if ((trb->control & TRB_C) != ring->ccs) {
+ return 0;
+ }
+
+ type = TRB_TYPE(*trb);
+
+ if (type != TR_LINK) {
+ if (addr) {
+ *addr = ring->dequeue;
+ }
+ ring->dequeue += TRB_SIZE;
+ return type;
+ } else {
+ ring->dequeue = xhci_mask64(trb->parameter);
+ if (trb->control & TRB_LK_TC) {
+ ring->ccs = !ring->ccs;
+ }
+ }
+ }
+}
+
+static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
+{
+ XHCITRB trb;
+ int length = 0;
+ target_phys_addr_t dequeue = ring->dequeue;
+ bool ccs = ring->ccs;
+ /* hack to bundle together the two/three TDs that make a setup transfer */
+ bool control_td_set = 0;
+
+ while (1) {
+ TRBType type;
+ cpu_physical_memory_read(dequeue, (uint8_t *) &trb, TRB_SIZE);
+ le64_to_cpus(&trb.parameter);
+ le32_to_cpus(&trb.status);
+ le32_to_cpus(&trb.control);
+
+ DPRINTF("xhci: TRB peeked [" TARGET_FMT_plx "]: "
+ "%016" PRIx64 " %08x %08x\n",
+ dequeue, trb.parameter, trb.status, trb.control);
+
+ if ((trb.control & TRB_C) != ccs) {
+ return -length;
+ }
+
+ type = TRB_TYPE(trb);
+
+ if (type == TR_LINK) {
+ dequeue = xhci_mask64(trb.parameter);
+ if (trb.control & TRB_LK_TC) {
+ ccs = !ccs;
+ }
+ continue;
+ }
+
+ length += 1;
+ dequeue += TRB_SIZE;
+
+ if (type == TR_SETUP) {
+ control_td_set = 1;
+ } else if (type == TR_STATUS) {
+ control_td_set = 0;
+ }
+
+ if (!control_td_set && !(trb.control & TRB_TR_CH)) {
+ return length;
+ }
+ }
+}
+
+static void xhci_er_reset(XHCIState *xhci)
+{
+ XHCIEvRingSeg seg;
+
+ /* cache the (sole) event ring segment location */
+ if (xhci->erstsz != 1) {
+ fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz);
+ xhci_die(xhci);
+ return;
+ }
+ target_phys_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high);
+ cpu_physical_memory_read(erstba, (uint8_t *) &seg, sizeof(seg));
+ le32_to_cpus(&seg.addr_low);
+ le32_to_cpus(&seg.addr_high);
+ le32_to_cpus(&seg.size);
+ if (seg.size < 16 || seg.size > 4096) {
+ fprintf(stderr, "xhci: invalid value for segment size: %d\n", seg.size);
+ xhci_die(xhci);
+ return;
+ }
+ xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high);
+ xhci->er_size = seg.size;
+
+ xhci->er_ep_idx = 0;
+ xhci->er_pcs = 1;
+ xhci->er_full = 0;
+
+ DPRINTF("xhci: event ring:" TARGET_FMT_plx " [%d]\n",
+ xhci->er_start, xhci->er_size);
+}
+
+static void xhci_run(XHCIState *xhci)
+{
+ DPRINTF("xhci_run()\n");
+
+ xhci->usbsts &= ~USBSTS_HCH;
+}
+
+static void xhci_stop(XHCIState *xhci)
+{
+ DPRINTF("xhci_stop()\n");
+ xhci->usbsts |= USBSTS_HCH;
+ xhci->crcr_low &= ~CRCR_CRR;
+}
+
+static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
+ uint32_t state)
+{
+ uint32_t ctx[5];
+ if (epctx->state == state) {
+ return;
+ }
+
+ cpu_physical_memory_read(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+ ctx[0] &= ~EP_STATE_MASK;
+ ctx[0] |= state;
+ ctx[2] = epctx->ring.dequeue | epctx->ring.ccs;
+ ctx[3] = (epctx->ring.dequeue >> 16) >> 16;
+ DPRINTF("xhci: set epctx: " TARGET_FMT_plx " state=%d dequeue=%08x%08x\n",
+ epctx->pctx, state, ctx[3], ctx[2]);
+ cpu_physical_memory_write(epctx->pctx, (uint8_t *) ctx, sizeof(ctx));
+ epctx->state = state;
+}
+
+static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid, target_phys_addr_t pctx,
+ uint32_t *ctx)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ target_phys_addr_t dequeue;
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+
+ DPRINTF("xhci_enable_ep(%d, %d)\n", slotid, epid);
+
+ slot = &xhci->slots[slotid-1];
+ if (slot->eps[epid-1]) {
+ fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid);
+ return CC_TRB_ERROR;
+ }
+
+ epctx = g_malloc(sizeof(XHCIEPContext));
+ memset(epctx, 0, sizeof(XHCIEPContext));
+
+ slot->eps[epid-1] = epctx;
+
+ dequeue = xhci_addr64(ctx[2] & ~0xf, ctx[3]);
+ xhci_ring_init(xhci, &epctx->ring, dequeue);
+ epctx->ring.ccs = ctx[2] & 1;
+
+ epctx->type = (ctx[1] >> EP_TYPE_SHIFT) & EP_TYPE_MASK;
+ DPRINTF("xhci: endpoint %d.%d type is %d\n", epid/2, epid%2, epctx->type);
+ epctx->pctx = pctx;
+ epctx->max_psize = ctx[1]>>16;
+ epctx->max_psize *= 1+((ctx[1]>>8)&0xff);
+ epctx->has_bg = false;
+ if (epctx->type == ET_ISO_IN) {
+ epctx->has_bg = true;
+ }
+ DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n",
+ epid/2, epid%2, epctx->max_psize);
+ for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) {
+ usb_packet_init(&epctx->transfers[i].packet);
+ }
+
+ epctx->state = EP_RUNNING;
+ ctx[0] &= ~EP_STATE_MASK;
+ ctx[0] |= EP_RUNNING;
+
+ return CC_SUCCESS;
+}
+
+static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ int i, xferi, killed = 0;
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+
+ DPRINTF("xhci_ep_nuke_xfers(%d, %d)\n", slotid, epid);
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ return 0;
+ }
+
+ epctx = slot->eps[epid-1];
+
+ xferi = epctx->next_xfer;
+ for (i = 0; i < TD_QUEUE; i++) {
+ XHCITransfer *t = &epctx->transfers[xferi];
+ if (t->running) {
+ t->cancelled = 1;
+ /* libusb_cancel_transfer(t->usbxfer) */
+ DPRINTF("xhci: cancelling transfer %d, waiting for it to complete...\n", i);
+ killed++;
+ }
+ if (t->backgrounded) {
+ t->backgrounded = 0;
+ }
+ if (t->trbs) {
+ g_free(t->trbs);
+ }
+ if (t->data) {
+ g_free(t->data);
+ }
+
+ t->trbs = NULL;
+ t->data = NULL;
+ t->trb_count = t->trb_alloced = 0;
+ t->data_length = t->data_alloced = 0;
+ xferi = (xferi + 1) % TD_QUEUE;
+ }
+ if (epctx->has_bg) {
+ xferi = epctx->next_bg;
+ for (i = 0; i < BG_XFERS; i++) {
+ XHCITransfer *t = &epctx->bg_transfers[xferi];
+ if (t->running) {
+ t->cancelled = 1;
+ /* libusb_cancel_transfer(t->usbxfer); */
+ DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i);
+ killed++;
+ }
+ if (t->data) {
+ g_free(t->data);
+ }
+
+ t->data = NULL;
+ xferi = (xferi + 1) % BG_XFERS;
+ }
+ }
+ return killed;
+}
+
+static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+
+ DPRINTF("xhci_disable_ep(%d, %d)\n", slotid, epid);
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d already disabled\n", slotid, epid);
+ return CC_SUCCESS;
+ }
+
+ xhci_ep_nuke_xfers(xhci, slotid, epid);
+
+ epctx = slot->eps[epid-1];
+
+ xhci_set_ep_state(xhci, epctx, EP_DISABLED);
+
+ g_free(epctx);
+ slot->eps[epid-1] = NULL;
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+
+ DPRINTF("xhci_stop_ep(%d, %d)\n", slotid, epid);
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+ if (epid < 1 || epid > 31) {
+ fprintf(stderr, "xhci: bad ep %d\n", epid);
+ return CC_TRB_ERROR;
+ }
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+ return CC_EP_NOT_ENABLED_ERROR;
+ }
+
+ if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) {
+ fprintf(stderr, "xhci: FIXME: endpoint stopped w/ xfers running, "
+ "data might be lost\n");
+ }
+
+ epctx = slot->eps[epid-1];
+
+ xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ USBDevice *dev;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+ DPRINTF("xhci_reset_ep(%d, %d)\n", slotid, epid);
+
+ if (epid < 1 || epid > 31) {
+ fprintf(stderr, "xhci: bad ep %d\n", epid);
+ return CC_TRB_ERROR;
+ }
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+ return CC_EP_NOT_ENABLED_ERROR;
+ }
+
+ epctx = slot->eps[epid-1];
+
+ if (epctx->state != EP_HALTED) {
+ fprintf(stderr, "xhci: reset EP while EP %d not halted (%d)\n",
+ epid, epctx->state);
+ return CC_CONTEXT_STATE_ERROR;
+ }
+
+ if (xhci_ep_nuke_xfers(xhci, slotid, epid) > 0) {
+ fprintf(stderr, "xhci: FIXME: endpoint reset w/ xfers running, "
+ "data might be lost\n");
+ }
+
+ uint8_t ep = epid>>1;
+
+ if (epid & 1) {
+ ep |= 0x80;
+ }
+
+ dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev;
+ if (!dev) {
+ return CC_USB_TRANSACTION_ERROR;
+ }
+
+ xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid,
+ unsigned int epid, uint64_t pdequeue)
+{
+ XHCISlot *slot;
+ XHCIEPContext *epctx;
+ target_phys_addr_t dequeue;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+
+ if (epid < 1 || epid > 31) {
+ fprintf(stderr, "xhci: bad ep %d\n", epid);
+ return CC_TRB_ERROR;
+ }
+
+ DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue);
+ dequeue = xhci_mask64(pdequeue);
+
+ slot = &xhci->slots[slotid-1];
+
+ if (!slot->eps[epid-1]) {
+ DPRINTF("xhci: slot %d ep %d not enabled\n", slotid, epid);
+ return CC_EP_NOT_ENABLED_ERROR;
+ }
+
+ epctx = slot->eps[epid-1];
+
+
+ if (epctx->state != EP_STOPPED) {
+ fprintf(stderr, "xhci: set EP dequeue pointer while EP %d not stopped\n", epid);
+ return CC_CONTEXT_STATE_ERROR;
+ }
+
+ xhci_ring_init(xhci, &epctx->ring, dequeue & ~0xF);
+ epctx->ring.ccs = dequeue & 1;
+
+ xhci_set_ep_state(xhci, epctx, EP_STOPPED);
+
+ return CC_SUCCESS;
+}
+
+static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data,
+ unsigned int length, bool in_xfer, bool out_xfer,
+ bool report)
+{
+ int i;
+ uint32_t edtla = 0;
+ unsigned int transferred = 0;
+ unsigned int left = length;
+ bool reported = 0;
+ bool shortpkt = 0;
+ XHCIEvent event = {ER_TRANSFER, CC_SUCCESS};
+ XHCIState *xhci = xfer->xhci;
+
+ DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n",
+ length, in_xfer, out_xfer, report);
+
+ assert(!(in_xfer && out_xfer));
+
+ for (i = 0; i < xfer->trb_count; i++) {
+ XHCITRB *trb = &xfer->trbs[i];
+ target_phys_addr_t addr;
+ unsigned int chunk = 0;
+
+ switch (TRB_TYPE(*trb)) {
+ case TR_DATA:
+ if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
+ fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n");
+ xhci_die(xhci);
+ return transferred;
+ }
+ /* fallthrough */
+ case TR_NORMAL:
+ case TR_ISOCH:
+ addr = xhci_mask64(trb->parameter);
+ chunk = trb->status & 0x1ffff;
+ if (chunk > left) {
+ chunk = left;
+ shortpkt = 1;
+ }
+ if (in_xfer || out_xfer) {
+ if (trb->control & TRB_TR_IDT) {
+ uint64_t idata;
+ if (chunk > 8 || in_xfer) {
+ fprintf(stderr, "xhci: invalid immediate data TRB\n");
+ xhci_die(xhci);
+ return transferred;
+ }
+ idata = le64_to_cpu(trb->parameter);
+ memcpy(data, &idata, chunk);
+ } else {
+ DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at "
+ TARGET_FMT_plx "\n", in_xfer, chunk, addr);
+ if (in_xfer) {
+ cpu_physical_memory_write(addr, data, chunk);
+ } else {
+ cpu_physical_memory_read(addr, data, chunk);
+ }
+#ifdef DEBUG_DATA
+ unsigned int count = chunk;
+ int i;
+ if (count > 16) {
+ count = 16;
+ }
+ DPRINTF(" ::");
+ for (i = 0; i < count; i++) {
+ DPRINTF(" %02x", data[i]);
+ }
+ DPRINTF("\n");
+#endif
+ }
+ }
+ left -= chunk;
+ data += chunk;
+ edtla += chunk;
+ transferred += chunk;
+ break;
+ case TR_STATUS:
+ reported = 0;
+ shortpkt = 0;
+ break;
+ }
+
+ if (report && !reported && (trb->control & TRB_TR_IOC ||
+ (shortpkt && (trb->control & TRB_TR_ISP)))) {
+ event.slotid = xfer->slotid;
+ event.epid = xfer->epid;
+ event.length = (trb->status & 0x1ffff) - chunk;
+ event.flags = 0;
+ event.ptr = trb->addr;
+ if (xfer->status == CC_SUCCESS) {
+ event.ccode = shortpkt ? CC_SHORT_PACKET : CC_SUCCESS;
+ } else {
+ event.ccode = xfer->status;
+ }
+ if (TRB_TYPE(*trb) == TR_EVDATA) {
+ event.ptr = trb->parameter;
+ event.flags |= TRB_EV_ED;
+ event.length = edtla & 0xffffff;
+ DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length);
+ edtla = 0;
+ }
+ xhci_event(xhci, &event);
+ reported = 1;
+ }
+ }
+ return transferred;
+}
+
+static void xhci_stall_ep(XHCITransfer *xfer)
+{
+ XHCIState *xhci = xfer->xhci;
+ XHCISlot *slot = &xhci->slots[xfer->slotid-1];
+ XHCIEPContext *epctx = slot->eps[xfer->epid-1];
+
+ epctx->ring.dequeue = xfer->trbs[0].addr;
+ epctx->ring.ccs = xfer->trbs[0].ccs;
+ xhci_set_ep_state(xhci, epctx, EP_HALTED);
+ DPRINTF("xhci: stalled slot %d ep %d\n", xfer->slotid, xfer->epid);
+ DPRINTF("xhci: will continue at "TARGET_FMT_plx"\n", epctx->ring.dequeue);
+}
+
+static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer,
+ XHCIEPContext *epctx);
+
+static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx)
+{
+ if (epctx->bg_updating) {
+ return;
+ }
+ DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx);
+ assert(epctx->has_bg);
+ DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg);
+ epctx->bg_updating = 1;
+ while (epctx->transfers[epctx->comp_xfer].backgrounded &&
+ epctx->bg_transfers[epctx->next_bg].complete) {
+ XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer];
+ XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg];
+#if 0
+ DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n",
+ epctx->comp_xfer, epctx->next_bg, bg->cur_pkt,
+ bg->usbxfer->iso_packet_desc[bg->cur_pkt].status
+ );
+#endif
+ assert(epctx->type == ET_ISO_IN);
+ assert(bg->iso_xfer);
+ assert(bg->in_xfer);
+ uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize;
+#if 0
+ int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length;
+ fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status);
+#else
+ int len = 0;
+ FIXME();
+#endif
+ fg->complete = 1;
+ fg->backgrounded = 0;
+
+ if (fg->status == CC_STALL_ERROR) {
+ xhci_stall_ep(fg);
+ }
+
+ xhci_xfer_data(fg, p, len, 1, 0, 1);
+
+ epctx->comp_xfer++;
+ if (epctx->comp_xfer == TD_QUEUE) {
+ epctx->comp_xfer = 0;
+ }
+ DPRINTF("next fg xfer: %d\n", epctx->comp_xfer);
+ bg->cur_pkt++;
+ if (bg->cur_pkt == bg->pkts) {
+ bg->complete = 0;
+ if (xhci_submit(xhci, bg, epctx) < 0) {
+ fprintf(stderr, "xhci: bg resubmit failed\n");
+ }
+ epctx->next_bg++;
+ if (epctx->next_bg == BG_XFERS) {
+ epctx->next_bg = 0;
+ }
+ DPRINTF("next bg xfer: %d\n", epctx->next_bg);
+
+ xhci_kick_ep(xhci, fg->slotid, fg->epid);
+ }
+ }
+ epctx->bg_updating = 0;
+}
+
+#if 0
+static void xhci_xfer_cb(struct libusb_transfer *transfer)
+{
+ XHCIState *xhci;
+ XHCITransfer *xfer;
+
+ xfer = (XHCITransfer *)transfer->user_data;
+ xhci = xfer->xhci;
+
+ DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid,
+ xfer->epid, transfer->status);
+
+ assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS);
+ assert(xfer->epid >= 1 && xfer->epid <= 31);
+
+ if (xfer->cancelled) {
+ DPRINTF("xhci: transfer cancelled, not reporting anything\n");
+ xfer->running = 0;
+ return;
+ }
+
+ XHCIEPContext *epctx;
+ XHCISlot *slot;
+ slot = &xhci->slots[xfer->slotid-1];
+ assert(slot->eps[xfer->epid-1]);
+ epctx = slot->eps[xfer->epid-1];
+
+ if (xfer->bg_xfer) {
+ DPRINTF("xhci: background transfer, updating\n");
+ xfer->complete = 1;
+ xfer->running = 0;
+ xhci_bg_update(xhci, epctx);
+ return;
+ }
+
+ if (xfer->iso_xfer) {
+ transfer->status = transfer->iso_packet_desc[0].status;
+ transfer->actual_length = transfer->iso_packet_desc[0].actual_length;
+ }
+
+ xfer->status = libusb_to_ccode(transfer->status);
+
+ xfer->complete = 1;
+ xfer->running = 0;
+
+ if (transfer->status == LIBUSB_TRANSFER_STALL)
+ xhci_stall_ep(xhci, epctx, xfer);
+
+ DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length);
+
+ if (xfer->in_xfer) {
+ if (xfer->epid == 1) {
+ xhci_xfer_data(xhci, xfer, xfer->data + 8,
+ transfer->actual_length, 1, 0, 1);
+ } else {
+ xhci_xfer_data(xhci, xfer, xfer->data,
+ transfer->actual_length, 1, 0, 1);
+ }
+ } else {
+ xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1);
+ }
+
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+}
+
+static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer,
+ uint8_t bmRequestType, uint8_t bRequest,
+ uint16_t wValue, uint16_t wIndex, uint16_t wLength)
+{
+ uint16_t type_req = (bmRequestType << 8) | bRequest;
+
+ switch (type_req) {
+ case 0x0000 | USB_REQ_SET_CONFIGURATION:
+ DPRINTF("xhci: HLE switch configuration\n");
+ return xhci_switch_config(xhci, xfer->slotid, wValue) == 0;
+ case 0x0100 | USB_REQ_SET_INTERFACE:
+ DPRINTF("xhci: HLE set interface altsetting\n");
+ return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0;
+ case 0x0200 | USB_REQ_CLEAR_FEATURE:
+ if (wValue == 0) { // endpoint halt
+ DPRINTF("xhci: HLE clear halt\n");
+ return xhci_clear_halt(xhci, xfer->slotid, wIndex);
+ }
+ case 0x0000 | USB_REQ_SET_ADDRESS:
+ fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n");
+ return 0;
+ default:
+ return 0;
+ }
+}
+#endif
+
+static int xhci_setup_packet(XHCITransfer *xfer, XHCIPort *port, int ep)
+{
+ usb_packet_setup(&xfer->packet,
+ xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT,
+ xfer->xhci->slots[xfer->slotid-1].devaddr,
+ ep & 0x7f);
+ usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length);
+ DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n",
+ xfer->packet.pid, xfer->packet.devaddr, xfer->packet.devep);
+ return 0;
+}
+
+static int xhci_complete_packet(XHCITransfer *xfer, int ret)
+{
+ if (ret == USB_RET_ASYNC) {
+ xfer->running = 1;
+ xfer->complete = 0;
+ xfer->cancelled = 0;
+ return 0;
+ } else {
+ xfer->running = 0;
+ xfer->complete = 1;
+ }
+
+ if (ret >= 0) {
+ xfer->status = CC_SUCCESS;
+ xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1);
+ return 0;
+ }
+
+ /* error */
+ switch (ret) {
+ case USB_RET_NODEV:
+ xfer->status = CC_USB_TRANSACTION_ERROR;
+ xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
+ xhci_stall_ep(xfer);
+ break;
+ case USB_RET_STALL:
+ xfer->status = CC_STALL_ERROR;
+ xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1);
+ xhci_stall_ep(xfer);
+ break;
+ default:
+ fprintf(stderr, "%s: FIXME: ret = %d\n", __FUNCTION__, ret);
+ FIXME();
+ }
+ return 0;
+}
+
+static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
+{
+ XHCITRB *trb_setup, *trb_status;
+ uint8_t bmRequestType, bRequest;
+ uint16_t wValue, wLength, wIndex;
+ XHCIPort *port;
+ USBDevice *dev;
+ int ret;
+
+ DPRINTF("xhci_fire_ctl_transfer(slot=%d)\n", xfer->slotid);
+
+ trb_setup = &xfer->trbs[0];
+ trb_status = &xfer->trbs[xfer->trb_count-1];
+
+ /* at most one Event Data TRB allowed after STATUS */
+ if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
+ trb_status--;
+ }
+
+ /* do some sanity checks */
+ if (TRB_TYPE(*trb_setup) != TR_SETUP) {
+ fprintf(stderr, "xhci: ep0 first TD not SETUP: %d\n",
+ TRB_TYPE(*trb_setup));
+ return -1;
+ }
+ if (TRB_TYPE(*trb_status) != TR_STATUS) {
+ fprintf(stderr, "xhci: ep0 last TD not STATUS: %d\n",
+ TRB_TYPE(*trb_status));
+ return -1;
+ }
+ if (!(trb_setup->control & TRB_TR_IDT)) {
+ fprintf(stderr, "xhci: Setup TRB doesn't have IDT set\n");
+ return -1;
+ }
+ if ((trb_setup->status & 0x1ffff) != 8) {
+ fprintf(stderr, "xhci: Setup TRB has bad length (%d)\n",
+ (trb_setup->status & 0x1ffff));
+ return -1;
+ }
+
+ bmRequestType = trb_setup->parameter;
+ bRequest = trb_setup->parameter >> 8;
+ wValue = trb_setup->parameter >> 16;
+ wIndex = trb_setup->parameter >> 32;
+ wLength = trb_setup->parameter >> 48;
+
+ if (xfer->data && xfer->data_alloced < wLength) {
+ xfer->data_alloced = 0;
+ g_free(xfer->data);
+ xfer->data = NULL;
+ }
+ if (!xfer->data) {
+ DPRINTF("xhci: alloc %d bytes data\n", wLength);
+ xfer->data = g_malloc(wLength+1);
+ xfer->data_alloced = wLength;
+ }
+ xfer->data_length = wLength;
+
+ port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
+ dev = port->port.dev;
+ if (!dev) {
+ fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
+ xhci->slots[xfer->slotid-1].port);
+ return -1;
+ }
+
+ xfer->in_xfer = bmRequestType & USB_DIR_IN;
+ xfer->iso_xfer = false;
+
+ xhci_setup_packet(xfer, port, 0);
+ if (!xfer->in_xfer) {
+ xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0);
+ }
+ ret = usb_device_handle_control(dev, &xfer->packet,
+ (bmRequestType << 8) | bRequest,
+ wValue, wIndex, wLength, xfer->data);
+
+ xhci_complete_packet(xfer, ret);
+ if (!xfer->running) {
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+ }
+ return 0;
+}
+
+static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
+{
+ XHCIPort *port;
+ USBDevice *dev;
+ int ret;
+
+ DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
+ uint8_t ep = xfer->epid>>1;
+
+ xfer->in_xfer = epctx->type>>2;
+ if (xfer->in_xfer) {
+ ep |= 0x80;
+ }
+
+ if (xfer->data && xfer->data_alloced < xfer->data_length) {
+ xfer->data_alloced = 0;
+ g_free(xfer->data);
+ xfer->data = NULL;
+ }
+ if (!xfer->data && xfer->data_length) {
+ DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length);
+ xfer->data = g_malloc(xfer->data_length);
+ xfer->data_alloced = xfer->data_length;
+ }
+ if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) {
+ if (!xfer->bg_xfer) {
+ xfer->pkts = 1;
+ }
+ } else {
+ xfer->pkts = 0;
+ }
+
+ port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1];
+ dev = port->port.dev;
+ if (!dev) {
+ fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid,
+ xhci->slots[xfer->slotid-1].port);
+ return -1;
+ }
+
+ xhci_setup_packet(xfer, port, ep);
+
+ switch(epctx->type) {
+ case ET_INTR_OUT:
+ case ET_INTR_IN:
+ case ET_BULK_OUT:
+ case ET_BULK_IN:
+ break;
+ case ET_ISO_OUT:
+ case ET_ISO_IN:
+ FIXME();
+ break;
+ default:
+ fprintf(stderr, "xhci: unknown or unhandled EP type %d (ep %02x)\n",
+ epctx->type, ep);
+ return -1;
+ }
+
+ if (!xfer->in_xfer) {
+ xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0);
+ }
+ ret = usb_handle_packet(dev, &xfer->packet);
+
+ xhci_complete_packet(xfer, ret);
+ if (!xfer->running) {
+ xhci_kick_ep(xhci, xfer->slotid, xfer->epid);
+ }
+ return 0;
+}
+
+static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx)
+{
+ int i;
+ unsigned int length = 0;
+ XHCITRB *trb;
+
+ DPRINTF("xhci_fire_transfer(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
+
+ for (i = 0; i < xfer->trb_count; i++) {
+ trb = &xfer->trbs[i];
+ if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) {
+ length += trb->status & 0x1ffff;
+ }
+ }
+ DPRINTF("xhci: total TD length=%d\n", length);
+
+ if (!epctx->has_bg) {
+ xfer->data_length = length;
+ xfer->backgrounded = 0;
+ return xhci_submit(xhci, xfer, epctx);
+ } else {
+ if (!epctx->bg_running) {
+ for (i = 0; i < BG_XFERS; i++) {
+ XHCITransfer *t = &epctx->bg_transfers[i];
+ t->xhci = xhci;
+ t->epid = xfer->epid;
+ t->slotid = xfer->slotid;
+ t->pkts = BG_PKTS;
+ t->pktsize = epctx->max_psize;
+ t->data_length = t->pkts * t->pktsize;
+ t->bg_xfer = 1;
+ if (xhci_submit(xhci, t, epctx) < 0) {
+ fprintf(stderr, "xhci: bg submit failed\n");
+ return -1;
+ }
+ }
+ epctx->bg_running = 1;
+ }
+ xfer->backgrounded = 1;
+ xhci_bg_update(xhci, epctx);
+ return 0;
+ }
+}
+
+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid)
+{
+ XHCIEPContext *epctx;
+ int length;
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ assert(epid >= 1 && epid <= 31);
+ DPRINTF("xhci_kick_ep(%d, %d)\n", slotid, epid);
+
+ if (!xhci->slots[slotid-1].enabled) {
+ fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid);
+ return;
+ }
+ epctx = xhci->slots[slotid-1].eps[epid-1];
+ if (!epctx) {
+ fprintf(stderr, "xhci: xhci_kick_ep for disabled endpoint %d,%d\n",
+ epid, slotid);
+ return;
+ }
+
+ if (epctx->state == EP_HALTED) {
+ DPRINTF("xhci: ep halted, not running schedule\n");
+ return;
+ }
+
+ xhci_set_ep_state(xhci, epctx, EP_RUNNING);
+
+ while (1) {
+ XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
+ if (xfer->running || xfer->backgrounded) {
+ DPRINTF("xhci: ep is busy\n");
+ break;
+ }
+ length = xhci_ring_chain_length(xhci, &epctx->ring);
+ if (length < 0) {
+ DPRINTF("xhci: incomplete TD (%d TRBs)\n", -length);
+ break;
+ } else if (length == 0) {
+ break;
+ }
+ DPRINTF("xhci: fetching %d-TRB TD\n", length);
+ if (xfer->trbs && xfer->trb_alloced < length) {
+ xfer->trb_count = 0;
+ xfer->trb_alloced = 0;
+ g_free(xfer->trbs);
+ xfer->trbs = NULL;
+ }
+ if (!xfer->trbs) {
+ xfer->trbs = g_malloc(sizeof(XHCITRB) * length);
+ xfer->trb_alloced = length;
+ }
+ xfer->trb_count = length;
+
+ for (i = 0; i < length; i++) {
+ assert(xhci_ring_fetch(xhci, &epctx->ring, &xfer->trbs[i], NULL));
+ }
+ xfer->xhci = xhci;
+ xfer->epid = epid;
+ xfer->slotid = slotid;
+
+ if (epid == 1) {
+ if (xhci_fire_ctl_transfer(xhci, xfer) >= 0) {
+ epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+ } else {
+ fprintf(stderr, "xhci: error firing CTL transfer\n");
+ }
+ } else {
+ if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) {
+ epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE;
+ } else {
+ fprintf(stderr, "xhci: error firing data transfer\n");
+ }
+ }
+
+ /*
+ * Qemu usb can't handle multiple in-flight xfers.
+ * Also xfers might be finished here already,
+ * possibly with an error. Stop here for now.
+ */
+ break;
+ }
+}
+
+static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
+{
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_enable_slot(%d)\n", slotid);
+ xhci->slots[slotid-1].enabled = 1;
+ xhci->slots[slotid-1].port = 0;
+ memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
+{
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_disable_slot(%d)\n", slotid);
+
+ for (i = 1; i <= 31; i++) {
+ if (xhci->slots[slotid-1].eps[i-1]) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ }
+
+ xhci->slots[slotid-1].enabled = 0;
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
+ uint64_t pictx, bool bsr)
+{
+ XHCISlot *slot;
+ USBDevice *dev;
+ target_phys_addr_t ictx, octx, dcbaap;
+ uint64_t poctx;
+ uint32_t ictl_ctx[2];
+ uint32_t slot_ctx[4];
+ uint32_t ep0_ctx[5];
+ unsigned int port;
+ int i;
+ TRBCCode res;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_address_slot(%d)\n", slotid);
+
+ dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
+ cpu_physical_memory_read(dcbaap + 8*slotid,
+ (uint8_t *) &poctx, sizeof(poctx));
+ ictx = xhci_mask64(pictx);
+ octx = xhci_mask64(le64_to_cpu(poctx));
+
+ DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+ if (ictl_ctx[0] != 0x0 || ictl_ctx[1] != 0x3) {
+ fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+ ictl_ctx[0], ictl_ctx[1]);
+ return CC_TRB_ERROR;
+ }
+
+ cpu_physical_memory_read(ictx+32, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ cpu_physical_memory_read(ictx+64, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+ DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+ DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
+ ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+ port = (slot_ctx[1]>>16) & 0xFF;
+ dev = xhci->ports[port-1].port.dev;
+
+ if (port < 1 || port > MAXPORTS) {
+ fprintf(stderr, "xhci: bad port %d\n", port);
+ return CC_TRB_ERROR;
+ } else if (!dev) {
+ fprintf(stderr, "xhci: port %d not connected\n", port);
+ return CC_USB_TRANSACTION_ERROR;
+ }
+
+ for (i = 0; i < MAXSLOTS; i++) {
+ if (xhci->slots[i].port == port) {
+ fprintf(stderr, "xhci: port %d already assigned to slot %d\n",
+ port, i+1);
+ return CC_TRB_ERROR;
+ }
+ }
+
+ slot = &xhci->slots[slotid-1];
+ slot->port = port;
+ slot->ctx = octx;
+
+ if (bsr) {
+ slot_ctx[3] = SLOT_DEFAULT << SLOT_STATE_SHIFT;
+ } else {
+ slot->devaddr = xhci->devaddr++;
+ slot_ctx[3] = (SLOT_ADDRESSED << SLOT_STATE_SHIFT) | slot->devaddr;
+ DPRINTF("xhci: device address is %d\n", slot->devaddr);
+ usb_device_handle_control(dev, NULL,
+ DeviceOutRequest | USB_REQ_SET_ADDRESS,
+ slot->devaddr, 0, 0, NULL);
+ }
+
+ res = xhci_enable_ep(xhci, slotid, 1, octx+32, ep0_ctx);
+
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+ DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
+ ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ cpu_physical_memory_write(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+ return res;
+}
+
+
+static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
+ uint64_t pictx, bool dc)
+{
+ target_phys_addr_t ictx, octx;
+ uint32_t ictl_ctx[2];
+ uint32_t slot_ctx[4];
+ uint32_t islot_ctx[4];
+ uint32_t ep_ctx[5];
+ int i;
+ TRBCCode res;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_configure_slot(%d)\n", slotid);
+
+ ictx = xhci_mask64(pictx);
+ octx = xhci->slots[slotid-1].ctx;
+
+ DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ if (dc) {
+ for (i = 2; i <= 31; i++) {
+ if (xhci->slots[slotid-1].eps[i-1]) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ }
+
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+ slot_ctx[3] |= SLOT_ADDRESSED << SLOT_STATE_SHIFT;
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ return CC_SUCCESS;
+ }
+
+ cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+ if ((ictl_ctx[0] & 0x3) != 0x0 || (ictl_ctx[1] & 0x3) != 0x1) {
+ fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+ ictl_ctx[0], ictl_ctx[1]);
+ return CC_TRB_ERROR;
+ }
+
+ cpu_physical_memory_read(ictx+32, (uint8_t *) islot_ctx, sizeof(islot_ctx));
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ if (SLOT_STATE(slot_ctx[3]) < SLOT_ADDRESSED) {
+ fprintf(stderr, "xhci: invalid slot state %08x\n", slot_ctx[3]);
+ return CC_CONTEXT_STATE_ERROR;
+ }
+
+ for (i = 2; i <= 31; i++) {
+ if (ictl_ctx[0] & (1<<i)) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ if (ictl_ctx[1] & (1<<i)) {
+ cpu_physical_memory_read(ictx+32+(32*i),
+ (uint8_t *) ep_ctx, sizeof(ep_ctx));
+ DPRINTF("xhci: input ep%d.%d context: %08x %08x %08x %08x %08x\n",
+ i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
+ ep_ctx[3], ep_ctx[4]);
+ xhci_disable_ep(xhci, slotid, i);
+ res = xhci_enable_ep(xhci, slotid, i, octx+(32*i), ep_ctx);
+ if (res != CC_SUCCESS) {
+ return res;
+ }
+ DPRINTF("xhci: output ep%d.%d context: %08x %08x %08x %08x %08x\n",
+ i/2, i%2, ep_ctx[0], ep_ctx[1], ep_ctx[2],
+ ep_ctx[3], ep_ctx[4]);
+ cpu_physical_memory_write(octx+(32*i),
+ (uint8_t *) ep_ctx, sizeof(ep_ctx));
+ }
+ }
+
+ slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+ slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT;
+ slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT);
+ slot_ctx[0] |= islot_ctx[0] & (SLOT_CONTEXT_ENTRIES_MASK <<
+ SLOT_CONTEXT_ENTRIES_SHIFT);
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ return CC_SUCCESS;
+}
+
+
+static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
+ uint64_t pictx)
+{
+ target_phys_addr_t ictx, octx;
+ uint32_t ictl_ctx[2];
+ uint32_t iep0_ctx[5];
+ uint32_t ep0_ctx[5];
+ uint32_t islot_ctx[4];
+ uint32_t slot_ctx[4];
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_evaluate_slot(%d)\n", slotid);
+
+ ictx = xhci_mask64(pictx);
+ octx = xhci->slots[slotid-1].ctx;
+
+ DPRINTF("xhci: input context at "TARGET_FMT_plx"\n", ictx);
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ cpu_physical_memory_read(ictx, (uint8_t *) ictl_ctx, sizeof(ictl_ctx));
+
+ if (ictl_ctx[0] != 0x0 || ictl_ctx[1] & ~0x3) {
+ fprintf(stderr, "xhci: invalid input context control %08x %08x\n",
+ ictl_ctx[0], ictl_ctx[1]);
+ return CC_TRB_ERROR;
+ }
+
+ if (ictl_ctx[1] & 0x1) {
+ cpu_physical_memory_read(ictx+32,
+ (uint8_t *) islot_ctx, sizeof(islot_ctx));
+
+ DPRINTF("xhci: input slot context: %08x %08x %08x %08x\n",
+ islot_ctx[0], islot_ctx[1], islot_ctx[2], islot_ctx[3]);
+
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ slot_ctx[1] &= ~0xFFFF; /* max exit latency */
+ slot_ctx[1] |= islot_ctx[1] & 0xFFFF;
+ slot_ctx[2] &= ~0xFF00000; /* interrupter target */
+ slot_ctx[2] |= islot_ctx[2] & 0xFF000000;
+
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ }
+
+ if (ictl_ctx[1] & 0x2) {
+ cpu_physical_memory_read(ictx+64,
+ (uint8_t *) iep0_ctx, sizeof(iep0_ctx));
+
+ DPRINTF("xhci: input ep0 context: %08x %08x %08x %08x %08x\n",
+ iep0_ctx[0], iep0_ctx[1], iep0_ctx[2],
+ iep0_ctx[3], iep0_ctx[4]);
+
+ cpu_physical_memory_read(octx+32, (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+
+ ep0_ctx[1] &= ~0xFFFF0000; /* max packet size*/
+ ep0_ctx[1] |= iep0_ctx[1] & 0xFFFF0000;
+
+ DPRINTF("xhci: output ep0 context: %08x %08x %08x %08x %08x\n",
+ ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]);
+
+ cpu_physical_memory_write(octx+32,
+ (uint8_t *) ep0_ctx, sizeof(ep0_ctx));
+ }
+
+ return CC_SUCCESS;
+}
+
+static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
+{
+ uint32_t slot_ctx[4];
+ target_phys_addr_t octx;
+ int i;
+
+ assert(slotid >= 1 && slotid <= MAXSLOTS);
+ DPRINTF("xhci_reset_slot(%d)\n", slotid);
+
+ octx = xhci->slots[slotid-1].ctx;
+
+ DPRINTF("xhci: output context at "TARGET_FMT_plx"\n", octx);
+
+ for (i = 2; i <= 31; i++) {
+ if (xhci->slots[slotid-1].eps[i-1]) {
+ xhci_disable_ep(xhci, slotid, i);
+ }
+ }
+
+ cpu_physical_memory_read(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+ slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT);
+ slot_ctx[3] |= SLOT_DEFAULT << SLOT_STATE_SHIFT;
+ DPRINTF("xhci: output slot context: %08x %08x %08x %08x\n",
+ slot_ctx[0], slot_ctx[1], slot_ctx[2], slot_ctx[3]);
+ cpu_physical_memory_write(octx, (uint8_t *) slot_ctx, sizeof(slot_ctx));
+
+ return CC_SUCCESS;
+}
+
+static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *trb)
+{
+ unsigned int slotid;
+ slotid = (trb->control >> TRB_CR_SLOTID_SHIFT) & TRB_CR_SLOTID_MASK;
+ if (slotid < 1 || slotid > MAXSLOTS) {
+ fprintf(stderr, "xhci: bad slot id %d\n", slotid);
+ event->ccode = CC_TRB_ERROR;
+ return 0;
+ } else if (!xhci->slots[slotid-1].enabled) {
+ fprintf(stderr, "xhci: slot id %d not enabled\n", slotid);
+ event->ccode = CC_SLOT_NOT_ENABLED_ERROR;
+ return 0;
+ }
+ return slotid;
+}
+
+static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx)
+{
+ target_phys_addr_t ctx;
+ uint8_t bw_ctx[MAXPORTS+1];
+
+ DPRINTF("xhci_get_port_bandwidth()\n");
+
+ ctx = xhci_mask64(pctx);
+
+ DPRINTF("xhci: bandwidth context at "TARGET_FMT_plx"\n", ctx);
+
+ /* TODO: actually implement real values here */
+ bw_ctx[0] = 0;
+ memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */
+ cpu_physical_memory_write(ctx, bw_ctx, sizeof(bw_ctx));
+
+ return CC_SUCCESS;
+}
+
+static uint32_t rotl(uint32_t v, unsigned count)
+{
+ count &= 31;
+ return (v << count) | (v >> (32 - count));
+}
+
+
+static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo)
+{
+ uint32_t val;
+ val = rotl(lo - 0x49434878, 32 - ((hi>>8) & 0x1F));
+ val += rotl(lo + 0x49434878, hi & 0x1F);
+ val -= rotl(hi ^ 0x49434878, (lo >> 16) & 0x1F);
+ return ~val;
+}
+
+static void xhci_via_challenge(uint64_t addr)
+{
+ uint32_t buf[8];
+ uint32_t obuf[8];
+ target_phys_addr_t paddr = xhci_mask64(addr);
+
+ cpu_physical_memory_read(paddr, (uint8_t *) &buf, 32);
+
+ memcpy(obuf, buf, sizeof(obuf));
+
+ if ((buf[0] & 0xff) == 2) {
+ obuf[0] = 0x49932000 + 0x54dc200 * buf[2] + 0x7429b578 * buf[3];
+ obuf[0] |= (buf[2] * buf[3]) & 0xff;
+ obuf[1] = 0x0132bb37 + 0xe89 * buf[2] + 0xf09 * buf[3];
+ obuf[2] = 0x0066c2e9 + 0x2091 * buf[2] + 0x19bd * buf[3];
+ obuf[3] = 0xd5281342 + 0x2cc9691 * buf[2] + 0x2367662 * buf[3];
+ obuf[4] = 0x0123c75c + 0x1595 * buf[2] + 0x19ec * buf[3];
+ obuf[5] = 0x00f695de + 0x26fd * buf[2] + 0x3e9 * buf[3];
+ obuf[6] = obuf[2] ^ obuf[3] ^ 0x29472956;
+ obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
+ }
+
+ cpu_physical_memory_write(paddr, (uint8_t *) &obuf, 32);
+}
+
+static void xhci_process_commands(XHCIState *xhci)
+{
+ XHCITRB trb;
+ TRBType type;
+ XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
+ target_phys_addr_t addr;
+ unsigned int i, slotid = 0;
+
+ DPRINTF("xhci_process_commands()\n");
+ if (!xhci_running(xhci)) {
+ DPRINTF("xhci_process_commands() called while xHC stopped or paused\n");
+ return;
+ }
+
+ xhci->crcr_low |= CRCR_CRR;
+
+ while ((type = xhci_ring_fetch(xhci, &xhci->cmd_ring, &trb, &addr))) {
+ event.ptr = addr;
+ switch (type) {
+ case CR_ENABLE_SLOT:
+ for (i = 0; i < MAXSLOTS; i++) {
+ if (!xhci->slots[i].enabled) {
+ break;
+ }
+ }
+ if (i >= MAXSLOTS) {
+ fprintf(stderr, "xhci: no device slots available\n");
+ event.ccode = CC_NO_SLOTS_ERROR;
+ } else {
+ slotid = i+1;
+ event.ccode = xhci_enable_slot(xhci, slotid);
+ }
+ break;
+ case CR_DISABLE_SLOT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_disable_slot(xhci, slotid);
+ }
+ break;
+ case CR_ADDRESS_DEVICE:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_address_slot(xhci, slotid, trb.parameter,
+ trb.control & TRB_CR_BSR);
+ }
+ break;
+ case CR_CONFIGURE_ENDPOINT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_configure_slot(xhci, slotid, trb.parameter,
+ trb.control & TRB_CR_DC);
+ }
+ break;
+ case CR_EVALUATE_CONTEXT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_evaluate_slot(xhci, slotid, trb.parameter);
+ }
+ break;
+ case CR_STOP_ENDPOINT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+ & TRB_CR_EPID_MASK;
+ event.ccode = xhci_stop_ep(xhci, slotid, epid);
+ }
+ break;
+ case CR_RESET_ENDPOINT:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+ & TRB_CR_EPID_MASK;
+ event.ccode = xhci_reset_ep(xhci, slotid, epid);
+ }
+ break;
+ case CR_SET_TR_DEQUEUE:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ unsigned int epid = (trb.control >> TRB_CR_EPID_SHIFT)
+ & TRB_CR_EPID_MASK;
+ event.ccode = xhci_set_ep_dequeue(xhci, slotid, epid,
+ trb.parameter);
+ }
+ break;
+ case CR_RESET_DEVICE:
+ slotid = xhci_get_slot(xhci, &event, &trb);
+ if (slotid) {
+ event.ccode = xhci_reset_slot(xhci, slotid);
+ }
+ break;
+ case CR_GET_PORT_BANDWIDTH:
+ event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
+ break;
+ case CR_VENDOR_VIA_CHALLENGE_RESPONSE:
+ xhci_via_challenge(trb.parameter);
+ break;
+ case CR_VENDOR_NEC_FIRMWARE_REVISION:
+ event.type = 48; /* NEC reply */
+ event.length = 0x3025;
+ break;
+ case CR_VENDOR_NEC_CHALLENGE_RESPONSE:
+ {
+ uint32_t chi = trb.parameter >> 32;
+ uint32_t clo = trb.parameter;
+ uint32_t val = xhci_nec_challenge(chi, clo);
+ event.length = val & 0xFFFF;
+ event.epid = val >> 16;
+ slotid = val >> 24;
+ event.type = 48; /* NEC reply */
+ }
+ break;
+ default:
+ fprintf(stderr, "xhci: unimplemented command %d\n", type);
+ event.ccode = CC_TRB_ERROR;
+ break;
+ }
+ event.slotid = slotid;
+ xhci_event(xhci, &event);
+ }
+}
+
+static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
+{
+ int nr = port->port.index + 1;
+
+ port->portsc = PORTSC_PP;
+ if (port->port.dev && !is_detach) {
+ port->portsc |= PORTSC_CCS;
+ switch (port->port.dev->speed) {
+ case USB_SPEED_LOW:
+ port->portsc |= PORTSC_SPEED_LOW;
+ break;
+ case USB_SPEED_FULL:
+ port->portsc |= PORTSC_SPEED_FULL;
+ break;
+ case USB_SPEED_HIGH:
+ port->portsc |= PORTSC_SPEED_HIGH;
+ break;
+ }
+ }
+
+ if (xhci_running(xhci)) {
+ port->portsc |= PORTSC_CSC;
+ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24};
+ xhci_event(xhci, &ev);
+ DPRINTF("xhci: port change event for port %d\n", nr);
+ }
+}
+
+static void xhci_reset(void *opaque)
+{
+ XHCIState *xhci = opaque;
+ int i;
+
+ DPRINTF("xhci: full reset\n");
+ if (!(xhci->usbsts & USBSTS_HCH)) {
+ fprintf(stderr, "xhci: reset while running!\n");
+ }
+
+ xhci->usbcmd = 0;
+ xhci->usbsts = USBSTS_HCH;
+ xhci->dnctrl = 0;
+ xhci->crcr_low = 0;
+ xhci->crcr_high = 0;
+ xhci->dcbaap_low = 0;
+ xhci->dcbaap_high = 0;
+ xhci->config = 0;
+ xhci->devaddr = 2;
+
+ for (i = 0; i < MAXSLOTS; i++) {
+ xhci_disable_slot(xhci, i+1);
+ }
+
+ for (i = 0; i < MAXPORTS; i++) {
+ xhci_update_port(xhci, xhci->ports + i, 0);
+ }
+
+ xhci->mfindex = 0;
+ xhci->iman = 0;
+ xhci->imod = 0;
+ xhci->erstsz = 0;
+ xhci->erstba_low = 0;
+ xhci->erstba_high = 0;
+ xhci->erdp_low = 0;
+ xhci->erdp_high = 0;
+
+ xhci->er_ep_idx = 0;
+ xhci->er_pcs = 1;
+ xhci->er_full = 0;
+ xhci->ev_buffer_put = 0;
+ xhci->ev_buffer_get = 0;
+}
+
+static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_cap_read(0x%x)\n", reg);
+
+ switch (reg) {
+ case 0x00: /* HCIVERSION, CAPLENGTH */
+ return 0x01000000 | LEN_CAP;
+ case 0x04: /* HCSPARAMS 1 */
+ return (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS;
+ case 0x08: /* HCSPARAMS 2 */
+ return 0x0000000f;
+ case 0x0c: /* HCSPARAMS 3 */
+ return 0x00000000;
+ case 0x10: /* HCCPARAMS */
+#if TARGET_PHYS_ADDR_BITS > 32
+ return 0x00081001;
+#else
+ return 0x00081000;
+#endif
+ case 0x14: /* DBOFF */
+ return OFF_DOORBELL;
+ case 0x18: /* RTSOFF */
+ return OFF_RUNTIME;
+
+ /* extended capabilities */
+ case 0x20: /* Supported Protocol:00 */
+#if USB3_PORTS > 0
+ return 0x02000402; /* USB 2.0 */
+#else
+ return 0x02000002; /* USB 2.0 */
+#endif
+ case 0x24: /* Supported Protocol:04 */
+ return 0x20425455; /* "USB " */
+ case 0x28: /* Supported Protocol:08 */
+ return 0x00000001 | (USB2_PORTS<<8);
+ case 0x2c: /* Supported Protocol:0c */
+ return 0x00000000; /* reserved */
+#if USB3_PORTS > 0
+ case 0x30: /* Supported Protocol:00 */
+ return 0x03000002; /* USB 3.0 */
+ case 0x34: /* Supported Protocol:04 */
+ return 0x20425455; /* "USB " */
+ case 0x38: /* Supported Protocol:08 */
+ return 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
+ case 0x3c: /* Supported Protocol:0c */
+ return 0x00000000; /* reserved */
+#endif
+ default:
+ fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg);
+ }
+ return 0;
+}
+
+static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
+{
+ uint32_t port = reg >> 4;
+ if (port >= MAXPORTS) {
+ fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
+ return 0;
+ }
+
+ switch (reg & 0xf) {
+ case 0x00: /* PORTSC */
+ return xhci->ports[port].portsc;
+ case 0x04: /* PORTPMSC */
+ case 0x08: /* PORTLI */
+ return 0;
+ case 0x0c: /* reserved */
+ default:
+ fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
+ port, reg);
+ return 0;
+ }
+}
+
+static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ uint32_t port = reg >> 4;
+ uint32_t portsc;
+
+ if (port >= MAXPORTS) {
+ fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
+ return;
+ }
+
+ switch (reg & 0xf) {
+ case 0x00: /* PORTSC */
+ portsc = xhci->ports[port].portsc;
+ /* write-1-to-clear bits*/
+ portsc &= ~(val & (PORTSC_CSC|PORTSC_PEC|PORTSC_WRC|PORTSC_OCC|
+ PORTSC_PRC|PORTSC_PLC|PORTSC_CEC));
+ if (val & PORTSC_LWS) {
+ /* overwrite PLS only when LWS=1 */
+ portsc &= ~(PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
+ portsc |= val & (PORTSC_PLS_MASK << PORTSC_PLS_SHIFT);
+ }
+ /* read/write bits */
+ portsc &= ~(PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE);
+ portsc |= (val & (PORTSC_PP|PORTSC_WCE|PORTSC_WDE|PORTSC_WOE));
+ /* write-1-to-start bits */
+ if (val & PORTSC_PR) {
+ DPRINTF("xhci: port %d reset\n", port);
+ if (xhci->ports[port].port.dev) {
+ usb_send_msg(xhci->ports[port].port.dev, USB_MSG_RESET);
+ }
+ portsc |= PORTSC_PRC | PORTSC_PED;
+ }
+ xhci->ports[port].portsc = portsc;
+ break;
+ case 0x04: /* PORTPMSC */
+ case 0x08: /* PORTLI */
+ default:
+ fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n",
+ port, reg);
+ }
+}
+
+static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_oper_read(0x%x)\n", reg);
+
+ if (reg >= 0x400) {
+ return xhci_port_read(xhci, reg - 0x400);
+ }
+
+ switch (reg) {
+ case 0x00: /* USBCMD */
+ return xhci->usbcmd;
+ case 0x04: /* USBSTS */
+ return xhci->usbsts;
+ case 0x08: /* PAGESIZE */
+ return 1; /* 4KiB */
+ case 0x14: /* DNCTRL */
+ return xhci->dnctrl;
+ case 0x18: /* CRCR low */
+ return xhci->crcr_low & ~0xe;
+ case 0x1c: /* CRCR high */
+ return xhci->crcr_high;
+ case 0x30: /* DCBAAP low */
+ return xhci->dcbaap_low;
+ case 0x34: /* DCBAAP high */
+ return xhci->dcbaap_high;
+ case 0x38: /* CONFIG */
+ return xhci->config;
+ default:
+ fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg);
+ }
+ return 0;
+}
+
+static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ DPRINTF("xhci_oper_write(0x%x, 0x%08x)\n", reg, val);
+
+ if (reg >= 0x400) {
+ xhci_port_write(xhci, reg - 0x400, val);
+ return;
+ }
+
+ switch (reg) {
+ case 0x00: /* USBCMD */
+ if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) {
+ xhci_run(xhci);
+ } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) {
+ xhci_stop(xhci);
+ }
+ xhci->usbcmd = val & 0xc0f;
+ if (val & USBCMD_HCRST) {
+ xhci_reset(xhci);
+ }
+ xhci_irq_update(xhci);
+ break;
+
+ case 0x04: /* USBSTS */
+ /* these bits are write-1-to-clear */
+ xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE));
+ xhci_irq_update(xhci);
+ break;
+
+ case 0x14: /* DNCTRL */
+ xhci->dnctrl = val & 0xffff;
+ break;
+ case 0x18: /* CRCR low */
+ xhci->crcr_low = (val & 0xffffffcf) | (xhci->crcr_low & CRCR_CRR);
+ break;
+ case 0x1c: /* CRCR high */
+ xhci->crcr_high = val;
+ if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) {
+ XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED};
+ xhci->crcr_low &= ~CRCR_CRR;
+ xhci_event(xhci, &event);
+ DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low);
+ } else {
+ target_phys_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val);
+ xhci_ring_init(xhci, &xhci->cmd_ring, base);
+ }
+ xhci->crcr_low &= ~(CRCR_CA | CRCR_CS);
+ break;
+ case 0x30: /* DCBAAP low */
+ xhci->dcbaap_low = val & 0xffffffc0;
+ break;
+ case 0x34: /* DCBAAP high */
+ xhci->dcbaap_high = val;
+ break;
+ case 0x38: /* CONFIG */
+ xhci->config = val & 0xff;
+ break;
+ default:
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
+ }
+}
+
+static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_runtime_read(0x%x)\n", reg);
+
+ switch (reg) {
+ case 0x00: /* MFINDEX */
+ fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n");
+ return xhci->mfindex;
+ case 0x20: /* IMAN */
+ return xhci->iman;
+ case 0x24: /* IMOD */
+ return xhci->imod;
+ case 0x28: /* ERSTSZ */
+ return xhci->erstsz;
+ case 0x30: /* ERSTBA low */
+ return xhci->erstba_low;
+ case 0x34: /* ERSTBA high */
+ return xhci->erstba_high;
+ case 0x38: /* ERDP low */
+ return xhci->erdp_low;
+ case 0x3c: /* ERDP high */
+ return xhci->erdp_high;
+ default:
+ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
+ }
+ return 0;
+}
+
+static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ DPRINTF("xhci_runtime_write(0x%x, 0x%08x)\n", reg, val);
+
+ switch (reg) {
+ case 0x20: /* IMAN */
+ if (val & IMAN_IP) {
+ xhci->iman &= ~IMAN_IP;
+ }
+ xhci->iman &= ~IMAN_IE;
+ xhci->iman |= val & IMAN_IE;
+ xhci_irq_update(xhci);
+ break;
+ case 0x24: /* IMOD */
+ xhci->imod = val;
+ break;
+ case 0x28: /* ERSTSZ */
+ xhci->erstsz = val & 0xffff;
+ break;
+ case 0x30: /* ERSTBA low */
+ /* XXX NEC driver bug: it doesn't align this to 64 bytes
+ xhci->erstba_low = val & 0xffffffc0; */
+ xhci->erstba_low = val & 0xfffffff0;
+ break;
+ case 0x34: /* ERSTBA high */
+ xhci->erstba_high = val;
+ xhci_er_reset(xhci);
+ break;
+ case 0x38: /* ERDP low */
+ if (val & ERDP_EHB) {
+ xhci->erdp_low &= ~ERDP_EHB;
+ }
+ xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB);
+ break;
+ case 0x3c: /* ERDP high */
+ xhci->erdp_high = val;
+ xhci_events_update(xhci);
+ break;
+ default:
+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg);
+ }
+}
+
+static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg)
+{
+ DPRINTF("xhci_doorbell_read(0x%x)\n", reg);
+ /* doorbells always read as 0 */
+ return 0;
+}
+
+static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val)
+{
+ DPRINTF("xhci_doorbell_write(0x%x, 0x%08x)\n", reg, val);
+
+ if (!xhci_running(xhci)) {
+ fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n");
+ return;
+ }
+
+ reg >>= 2;
+
+ if (reg == 0) {
+ if (val == 0) {
+ xhci_process_commands(xhci);
+ } else {
+ fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val);
+ }
+ } else {
+ if (reg > MAXSLOTS) {
+ fprintf(stderr, "xhci: bad doorbell %d\n", reg);
+ } else if (val > 31) {
+ fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val);
+ } else {
+ xhci_kick_ep(xhci, reg, val);
+ }
+ }
+}
+
+static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr,
+ unsigned size)
+{
+ XHCIState *xhci = ptr;
+
+ /* Only aligned reads are allowed on xHCI */
+ if (addr & 3) {
+ fprintf(stderr, "xhci_mem_read: Mis-aligned read\n");
+ return 0;
+ }
+
+ if (addr < LEN_CAP) {
+ return xhci_cap_read(xhci, addr);
+ } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
+ return xhci_oper_read(xhci, addr - OFF_OPER);
+ } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
+ return xhci_runtime_read(xhci, addr - OFF_RUNTIME);
+ } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
+ return xhci_doorbell_read(xhci, addr - OFF_DOORBELL);
+ } else {
+ fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr);
+ return 0;
+ }
+}
+
+static void xhci_mem_write(void *ptr, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
+{
+ XHCIState *xhci = ptr;
+
+ /* Only aligned writes are allowed on xHCI */
+ if (addr & 3) {
+ fprintf(stderr, "xhci_mem_write: Mis-aligned write\n");
+ return;
+ }
+
+ if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) {
+ xhci_oper_write(xhci, addr - OFF_OPER, val);
+ } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) {
+ xhci_runtime_write(xhci, addr - OFF_RUNTIME, val);
+ } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) {
+ xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val);
+ } else {
+ fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr);
+ }
+}
+
+static const MemoryRegionOps xhci_mem_ops = {
+ .read = xhci_mem_read,
+ .write = xhci_mem_write,
+ .valid.min_access_size = 4,
+ .valid.max_access_size = 4,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static void xhci_attach(USBPort *usbport)
+{
+ XHCIState *xhci = usbport->opaque;
+ XHCIPort *port = &xhci->ports[usbport->index];
+
+ xhci_update_port(xhci, port, 0);
+}
+
+static void xhci_detach(USBPort *usbport)
+{
+ XHCIState *xhci = usbport->opaque;
+ XHCIPort *port = &xhci->ports[usbport->index];
+
+ xhci_update_port(xhci, port, 1);
+}
+
+static void xhci_complete(USBPort *port, USBPacket *packet)
+{
+ XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
+
+ xhci_complete_packet(xfer, packet->result);
+ xhci_kick_ep(xfer->xhci, xfer->slotid, xfer->epid);
+}
+
+static void xhci_child_detach(USBPort *port, USBDevice *child)
+{
+ FIXME();
+}
+
+static USBPortOps xhci_port_ops = {
+ .attach = xhci_attach,
+ .detach = xhci_detach,
+ .complete = xhci_complete,
+ .child_detach = xhci_child_detach,
+};
+
+static USBBusOps xhci_bus_ops = {
+};
+
+static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
+{
+ int i;
+
+ xhci->usbsts = USBSTS_HCH;
+
+ usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev);
+
+ for (i = 0; i < MAXPORTS; i++) {
+ memset(&xhci->ports[i], 0, sizeof(xhci->ports[i]));
+ usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i,
+ &xhci_port_ops, USB_SPEED_MASK_HIGH);
+ }
+ for (i = 0; i < MAXSLOTS; i++) {
+ xhci->slots[i].enabled = 0;
+ }
+
+ qemu_register_reset(xhci_reset, xhci);
+}
+
+static int usb_xhci_initfn(struct PCIDevice *dev)
+{
+ int ret;
+
+ XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
+
+ xhci->pci_dev.config[PCI_CLASS_PROG] = 0x30; /* xHCI */
+ xhci->pci_dev.config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin 1 */
+ xhci->pci_dev.config[PCI_CACHE_LINE_SIZE] = 0x10;
+ xhci->pci_dev.config[0x60] = 0x30; /* release number */
+
+ usb_xhci_init(xhci, &dev->qdev);
+
+ xhci->irq = xhci->pci_dev.irq[0];
+
+ memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci,
+ "xhci", LEN_REGS);
+ pci_register_bar(&xhci->pci_dev, 0,
+ PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64,
+ &xhci->mem);
+
+ ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0);
+ assert(ret >= 0);
+
+ if (xhci->msi) {
+ ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false);
+ assert(ret >= 0);
+ }
+
+ return 0;
+}
+
+static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val,
+ int len)
+{
+ XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev);
+
+ pci_default_write_config(dev, addr, val, len);
+ if (xhci->msi) {
+ msi_write_config(dev, addr, val, len);
+ }
+}
+
+static const VMStateDescription vmstate_xhci = {
+ .name = "xhci",
+ .unmigratable = 1,
+};
+
+static Property xhci_properties[] = {
+ DEFINE_PROP_UINT32("msi", XHCIState, msi, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xhci_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->vmsd = &vmstate_xhci;
+ dc->props = xhci_properties;
+ k->init = usb_xhci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_NEC;
+ k->device_id = PCI_DEVICE_ID_NEC_UPD720200;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ k->revision = 0x03;
+ k->is_express = 1;
+ k->config_write = xhci_write_config;
+}
+
+static TypeInfo xhci_info = {
+ .name = "nec-usb-xhci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(XHCIState),
+ .class_init = xhci_class_init,
+};
+
+static void xhci_register(void)
+{
+ type_register_static(&xhci_info);
+}
+device_init(xhci_register);
diff --git a/hw/usb.c b/hw/usb.c
index 2216efe077..c3ff5b7093 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -95,8 +95,8 @@ static int do_token_setup(USBDevice *s, USBPacket *p)
index = (s->setup_buf[5] << 8) | s->setup_buf[4];
if (s->setup_buf[0] & USB_DIR_IN) {
- ret = s->info->handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
+ ret = usb_device_handle_control(s, p, request, value, index,
+ s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
s->setup_state = SETUP_STATE_SETUP;
return USB_RET_ASYNC;
@@ -129,7 +129,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
int ret = 0;
if (p->devep != 0)
- return s->info->handle_data(s, p);
+ return usb_device_handle_data(s, p);
request = (s->setup_buf[0] << 8) | s->setup_buf[1];
value = (s->setup_buf[3] << 8) | s->setup_buf[2];
@@ -138,8 +138,8 @@ static int do_token_in(USBDevice *s, USBPacket *p)
switch(s->setup_state) {
case SETUP_STATE_ACK:
if (!(s->setup_buf[0] & USB_DIR_IN)) {
- ret = s->info->handle_control(s, p, request, value, index,
- s->setup_len, s->data_buf);
+ ret = usb_device_handle_control(s, p, request, value, index,
+ s->setup_len, s->data_buf);
if (ret == USB_RET_ASYNC) {
return USB_RET_ASYNC;
}
@@ -176,7 +176,7 @@ static int do_token_in(USBDevice *s, USBPacket *p)
static int do_token_out(USBDevice *s, USBPacket *p)
{
if (p->devep != 0)
- return s->info->handle_data(s, p);
+ return usb_device_handle_data(s, p);
switch(s->setup_state) {
case SETUP_STATE_ACK:
@@ -220,9 +220,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
switch(p->pid) {
case USB_MSG_ATTACH:
s->state = USB_STATE_ATTACHED;
- if (s->info->handle_attach) {
- s->info->handle_attach(s);
- }
+ usb_device_handle_attach(s);
return 0;
case USB_MSG_DETACH:
@@ -233,9 +231,7 @@ int usb_generic_handle_packet(USBDevice *s, USBPacket *p)
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
- if (s->info->handle_reset) {
- s->info->handle_reset(s);
- }
+ usb_device_handle_reset(s);
return 0;
}
@@ -326,10 +322,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p)
int ret;
assert(p->owner == NULL);
- ret = dev->info->handle_packet(dev, p);
+ ret = usb_device_handle_packet(dev, p);
if (ret == USB_RET_ASYNC) {
if (p->owner == NULL) {
- p->owner = dev;
+ p->owner = usb_ep_get(dev, p->pid, p->devep);
} else {
/* We'll end up here when usb_handle_packet is called
* recursively due to a hub being in the chain. Nothing
@@ -357,7 +353,7 @@ void usb_packet_complete(USBDevice *dev, USBPacket *p)
void usb_cancel_packet(USBPacket * p)
{
assert(p->owner != NULL);
- p->owner->info->cancel_packet(p->owner, p);
+ usb_device_cancel_packet(p->owner->dev, p);
p->owner = NULL;
}
@@ -414,3 +410,124 @@ void usb_packet_cleanup(USBPacket *p)
{
qemu_iovec_destroy(&p->iov);
}
+
+void usb_ep_init(USBDevice *dev)
+{
+ int ep;
+
+ dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL;
+ dev->ep_ctl.ifnum = 0;
+ dev->ep_ctl.dev = dev;
+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+ dev->ep_in[ep].type = USB_ENDPOINT_XFER_INVALID;
+ dev->ep_out[ep].type = USB_ENDPOINT_XFER_INVALID;
+ dev->ep_in[ep].ifnum = 0;
+ dev->ep_out[ep].ifnum = 0;
+ dev->ep_in[ep].dev = dev;
+ dev->ep_out[ep].dev = dev;
+ }
+}
+
+void usb_ep_dump(USBDevice *dev)
+{
+ static const char *tname[] = {
+ [USB_ENDPOINT_XFER_CONTROL] = "control",
+ [USB_ENDPOINT_XFER_ISOC] = "isoc",
+ [USB_ENDPOINT_XFER_BULK] = "bulk",
+ [USB_ENDPOINT_XFER_INT] = "int",
+ };
+ int ifnum, ep, first;
+
+ fprintf(stderr, "Device \"%s\", config %d\n",
+ dev->product_desc, dev->configuration);
+ for (ifnum = 0; ifnum < 16; ifnum++) {
+ first = 1;
+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) {
+ if (dev->ep_in[ep].type != USB_ENDPOINT_XFER_INVALID &&
+ dev->ep_in[ep].ifnum == ifnum) {
+ if (first) {
+ first = 0;
+ fprintf(stderr, " Interface %d, alternative %d\n",
+ ifnum, dev->altsetting[ifnum]);
+ }
+ fprintf(stderr, " Endpoint %d, IN, %s, %d max\n", ep,
+ tname[dev->ep_in[ep].type],
+ dev->ep_in[ep].max_packet_size);
+ }
+ if (dev->ep_out[ep].type != USB_ENDPOINT_XFER_INVALID &&
+ dev->ep_out[ep].ifnum == ifnum) {
+ if (first) {
+ first = 0;
+ fprintf(stderr, " Interface %d, alternative %d\n",
+ ifnum, dev->altsetting[ifnum]);
+ }
+ fprintf(stderr, " Endpoint %d, OUT, %s, %d max\n", ep,
+ tname[dev->ep_out[ep].type],
+ dev->ep_out[ep].max_packet_size);
+ }
+ }
+ }
+ fprintf(stderr, "--\n");
+}
+
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *eps = pid == USB_TOKEN_IN ? dev->ep_in : dev->ep_out;
+ if (ep == 0) {
+ return &dev->ep_ctl;
+ }
+ assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
+ assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
+ return eps + ep - 1;
+}
+
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ return uep->type;
+}
+
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ uep->type = type;
+}
+
+uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ return uep->ifnum;
+}
+
+void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ uep->ifnum = ifnum;
+}
+
+void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
+ uint16_t raw)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ int size, microframes;
+
+ size = raw & 0x7ff;
+ switch ((raw >> 11) & 3) {
+ case 1:
+ microframes = 2;
+ break;
+ case 2:
+ microframes = 3;
+ break;
+ default:
+ microframes = 1;
+ break;
+ }
+ uep->max_packet_size = size * microframes;
+}
+
+int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep)
+{
+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep);
+ return uep->max_packet_size;
+}
diff --git a/hw/usb.h b/hw/usb.h
index 7ea90e4d9c..13e7c8ea7f 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -1,3 +1,6 @@
+#ifndef QEMU_USB_H
+#define QEMU_USB_H
+
/*
* QEMU USB API
*
@@ -79,6 +82,11 @@
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
+#define USB_SUBCLASS_UNDEFINED 0
+#define USB_SUBCLASS_AUDIO_CONTROL 1
+#define USB_SUBCLASS_AUDIO_STREAMING 2
+#define USB_SUBCLASS_AUDIO_MIDISTREAMING 3
+
#define USB_DIR_OUT 0
#define USB_DIR_IN 0x80
@@ -132,18 +140,21 @@
#define USB_DT_OTHER_SPEED_CONFIG 0x07
#define USB_DT_DEBUG 0x0A
#define USB_DT_INTERFACE_ASSOC 0x0B
+#define USB_DT_CS_INTERFACE 0x24
+#define USB_DT_CS_ENDPOINT 0x25
#define USB_ENDPOINT_XFER_CONTROL 0
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_XFER_INVALID 255
typedef struct USBBus USBBus;
typedef struct USBBusOps USBBusOps;
typedef struct USBPort USBPort;
typedef struct USBDevice USBDevice;
-typedef struct USBDeviceInfo USBDeviceInfo;
typedef struct USBPacket USBPacket;
+typedef struct USBEndpoint USBEndpoint;
typedef struct USBDesc USBDesc;
typedef struct USBDescID USBDescID;
@@ -161,10 +172,19 @@ struct USBDescString {
QLIST_ENTRY(USBDescString) next;
};
+#define USB_MAX_ENDPOINTS 15
+#define USB_MAX_INTERFACES 16
+
+struct USBEndpoint {
+ uint8_t type;
+ uint8_t ifnum;
+ int max_packet_size;
+ USBDevice *dev;
+};
+
/* definition of a USB device */
struct USBDevice {
DeviceState qdev;
- USBDeviceInfo *info;
USBPort *port;
char *port_path;
void *opaque;
@@ -186,13 +206,31 @@ struct USBDevice {
int32_t setup_len;
int32_t setup_index;
+ USBEndpoint ep_ctl;
+ USBEndpoint ep_in[USB_MAX_ENDPOINTS];
+ USBEndpoint ep_out[USB_MAX_ENDPOINTS];
+
QLIST_HEAD(, USBDescString) strings;
const USBDescDevice *device;
+
+ int configuration;
+ int ninterfaces;
+ int altsetting[USB_MAX_INTERFACES];
const USBDescConfig *config;
+ const USBDescIface *ifaces[USB_MAX_INTERFACES];
};
-struct USBDeviceInfo {
- DeviceInfo qdev;
+#define TYPE_USB_DEVICE "usb-device"
+#define USB_DEVICE(obj) \
+ OBJECT_CHECK(USBDevice, (obj), TYPE_USB_DEVICE)
+#define USB_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(USBDeviceClass, (klass), TYPE_USB_DEVICE)
+#define USB_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(USBDeviceClass, (obj), TYPE_USB_DEVICE)
+
+typedef struct USBDeviceClass {
+ DeviceClass parent_class;
+
int (*init)(USBDevice *dev);
/*
@@ -241,13 +279,12 @@ struct USBDeviceInfo {
*/
int (*handle_data)(USBDevice *dev, USBPacket *p);
+ void (*set_interface)(USBDevice *dev, int interface,
+ int alt_old, int alt_new);
+
const char *product_desc;
const USBDesc *usb_desc;
-
- /* handle legacy -usbdevice command line options */
- const char *usbdevice_name;
- USBDevice *(*usbdevice_init)(const char *params);
-};
+} USBDeviceClass;
typedef struct USBPortOps {
void (*attach)(USBPort *port);
@@ -288,7 +325,7 @@ struct USBPacket {
QEMUIOVector iov;
int result; /* transfer length or USB_RET_* status code */
/* Internal use by the USB layer. */
- USBDevice *owner;
+ USBEndpoint *owner;
};
void usb_packet_init(USBPacket *p);
@@ -304,6 +341,17 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p);
void usb_packet_complete(USBDevice *dev, USBPacket *p);
void usb_cancel_packet(USBPacket * p);
+void usb_ep_init(USBDevice *dev);
+void usb_ep_dump(USBDevice *dev);
+struct USBEndpoint *usb_ep_get(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_type(USBDevice *dev, int pid, int ep);
+uint8_t usb_ep_get_ifnum(USBDevice *dev, int pid, int ep);
+void usb_ep_set_type(USBDevice *dev, int pid, int ep, uint8_t type);
+void usb_ep_set_ifnum(USBDevice *dev, int pid, int ep, uint8_t ifnum);
+void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep,
+ uint16_t raw);
+int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep);
+
void usb_attach(USBPort *port);
void usb_detach(USBPort *port);
void usb_reset(USBPort *port);
@@ -370,8 +418,8 @@ struct USBBusOps {
void usb_bus_new(USBBus *bus, USBBusOps *ops, DeviceState *host);
USBBus *usb_bus_find(int busnr);
-void usb_qdev_register(USBDeviceInfo *info);
-void usb_qdev_register_many(USBDeviceInfo *info);
+void usb_legacy_register(const char *typename, const char *usbdevice_name,
+ USBDevice *(*usbdevice_init)(const char *params));
USBDevice *usb_create(USBBus *bus, const char *name);
USBDevice *usb_create_simple(USBBus *bus, const char *name);
USBDevice *usbdevice_create(const char *cmdline);
@@ -403,4 +451,25 @@ extern const VMStateDescription vmstate_usb_device;
.offset = vmstate_offset_value(_state, _field, USBDevice), \
}
+int usb_device_handle_packet(USBDevice *dev, USBPacket *p);
+
+void usb_device_cancel_packet(USBDevice *dev, USBPacket *p);
+
+void usb_device_handle_attach(USBDevice *dev);
+
+void usb_device_handle_reset(USBDevice *dev);
+
+int usb_device_handle_control(USBDevice *dev, USBPacket *p, int request, int value,
+ int index, int length, uint8_t *data);
+
+int usb_device_handle_data(USBDevice *dev, USBPacket *p);
+
+void usb_device_set_interface(USBDevice *dev, int interface,
+ int alt_old, int alt_new);
+
+const char *usb_device_get_product_desc(USBDevice *dev);
+
+const USBDesc *usb_device_get_usb_desc(USBDevice *dev);
+
+#endif
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index a285f7f383..c4105e977b 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -109,22 +109,56 @@ static int versatile_pci_host_init(PCIDevice *d)
return 0;
}
-static PCIDeviceInfo versatile_pci_host_info = {
- .qdev.name = "versatile_pci_host",
- .qdev.size = sizeof(PCIDevice),
- .init = versatile_pci_host_init,
- .vendor_id = PCI_VENDOR_ID_XILINX,
- /* Both boards have the same device ID. Oh well. */
- .device_id = PCI_DEVICE_ID_XILINX_XC2VP30,
- .class_id = PCI_CLASS_PROCESSOR_CO,
+static void versatile_pci_host_class_init(ObjectClass *klass, void *data)
+{
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = versatile_pci_host_init;
+ k->vendor_id = PCI_VENDOR_ID_XILINX;
+ k->device_id = PCI_DEVICE_ID_XILINX_XC2VP30;
+ k->class_id = PCI_CLASS_PROCESSOR_CO;
+}
+
+static TypeInfo versatile_pci_host_info = {
+ .name = "versatile_pci_host",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIDevice),
+ .class_init = versatile_pci_host_class_init,
+};
+
+static void pci_vpb_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pci_vpb_init;
+}
+
+static TypeInfo pci_vpb_info = {
+ .name = "versatile_pci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PCIVPBState),
+ .class_init = pci_vpb_class_init,
+};
+
+static void pci_realview_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = pci_realview_init;
+}
+
+static TypeInfo pci_realview_info = {
+ .name = "realview_pci",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(PCIVPBState),
+ .class_init = pci_realview_class_init,
};
static void versatile_pci_register_devices(void)
{
- sysbus_register_dev("versatile_pci", sizeof(PCIVPBState), pci_vpb_init);
- sysbus_register_dev("realview_pci", sizeof(PCIVPBState),
- pci_realview_init);
- pci_qdev_register(&versatile_pci_host_info);
+ type_register_static(&pci_vpb_info);
+ type_register_static(&pci_realview_info);
+ type_register_static(&versatile_pci_host_info);
}
device_init(versatile_pci_register_devices)
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index 0312b7564a..6e28e78f44 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -365,17 +365,26 @@ static void versatile_machine_init(void)
machine_init(versatile_machine_init);
-static SysBusDeviceInfo vpb_sic_info = {
- .init = vpb_sic_init,
- .qdev.name = "versatilepb_sic",
- .qdev.size = sizeof(vpb_sic_state),
- .qdev.vmsd = &vmstate_vpb_sic,
- .qdev.no_user = 1,
+static void vpb_sic_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = vpb_sic_init;
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_vpb_sic;
+}
+
+static TypeInfo vpb_sic_info = {
+ .name = "versatilepb_sic",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(vpb_sic_state),
+ .class_init = vpb_sic_class_init,
};
static void versatilepb_register_devices(void)
{
- sysbus_register_withprop(&vpb_sic_info);
+ type_register_static(&vpb_sic_info);
}
device_init(versatilepb_register_devices)
diff --git a/hw/vexpress.c b/hw/vexpress.c
index 71115564e0..64fab4574c 100644
--- a/hw/vexpress.c
+++ b/hw/vexpress.c
@@ -182,6 +182,7 @@ static void vexpress_a9_init(ram_addr_t ram_size,
/* 0x100ec000 TrustZone Address Space Controller */
/* 0x10200000 CoreSight debug APB */
/* 0x1e00a000 PL310 L2 Cache Controller */
+ sysbus_create_varargs("l2x0", 0x1e00a000, NULL);
/* CS0: NOR0 flash : 0x40000000 .. 0x44000000 */
/* CS4: NOR1 flash : 0x44000000 .. 0x48000000 */
diff --git a/hw/vga-isa.c b/hw/vga-isa.c
index 4825313f67..8d3ff0d47b 100644
--- a/hw/vga-isa.c
+++ b/hw/vga-isa.c
@@ -69,16 +69,24 @@ static int vga_initfn(ISADevice *dev)
return 0;
}
-static ISADeviceInfo vga_info = {
- .qdev.name = "isa-vga",
- .qdev.size = sizeof(ISAVGAState),
- .qdev.vmsd = &vmstate_vga_common,
- .qdev.reset = vga_reset_isa,
- .init = vga_initfn,
+static void vga_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = vga_initfn;
+ dc->reset = vga_reset_isa;
+ dc->vmsd = &vmstate_vga_common;
+}
+
+static TypeInfo vga_info = {
+ .name = "isa-vga",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(ISAVGAState),
+ .class_init = vga_class_initfn,
};
static void vga_register(void)
{
- isa_qdev_register(&vga_info);
+ type_register_static(&vga_info);
}
device_init(vga_register)
diff --git a/hw/vga-pci.c b/hw/vga-pci.c
index a75dbf3974..974a7a9d6f 100644
--- a/hw/vga-pci.c
+++ b/hw/vga-pci.c
@@ -75,22 +75,29 @@ DeviceState *pci_vga_init(PCIBus *bus)
return &pci_create_simple(bus, -1, "VGA")->qdev;
}
-static PCIDeviceInfo vga_info = {
- .qdev.name = "VGA",
- .qdev.size = sizeof(PCIVGAState),
- .qdev.vmsd = &vmstate_vga_pci,
- .no_hotplug = 1,
- .init = pci_vga_initfn,
- .romfile = "vgabios-stdvga.bin",
+static void vga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_vga_initfn;
+ k->romfile = "vgabios-stdvga.bin";
+ k->vendor_id = PCI_VENDOR_ID_QEMU;
+ k->device_id = PCI_DEVICE_ID_QEMU_VGA;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ dc->vmsd = &vmstate_vga_pci;
+}
- /* dummy VGA (same as Bochs ID) */
- .vendor_id = PCI_VENDOR_ID_QEMU,
- .device_id = PCI_DEVICE_ID_QEMU_VGA,
- .class_id = PCI_CLASS_DISPLAY_VGA,
+static TypeInfo vga_info = {
+ .name = "VGA",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIVGAState),
+ .class_init = vga_class_init,
};
static void vga_register(void)
{
- pci_qdev_register(&vga_info);
+ type_register_static(&vga_info);
}
device_init(vga_register);
diff --git a/hw/vga.c b/hw/vga.c
index 950f97e440..d87c4f9f5b 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "hw.h"
+#include "vga.h"
#include "console.h"
#include "pc.h"
#include "pci.h"
@@ -36,6 +37,18 @@
//#define DEBUG_BOCHS_VBE
+/*
+ * Video Graphics Array (VGA)
+ *
+ * Chipset docs for original IBM VGA:
+ * http://www.mcamafia.de/pdf/ibm_vgaxga_trm2.pdf
+ *
+ * FreeVGA site:
+ * http://www.osdever.net/FreeVGA/home.htm
+ *
+ * Standard VGA features and Bochs VBE extensions are implemented.
+ */
+
/* force some bits to zero */
const uint8_t sr_mask[8] = {
0x03,
@@ -160,9 +173,10 @@ static void vga_update_memory_access(VGACommonState *s)
s->chain4_alias = NULL;
- if ((s->sr[0x02] & 0xf) == 0xf && s->sr[0x04] & 0x08) {
+ if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
+ VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
offset = 0;
- switch ((s->gr[6] >> 2) & 3) {
+ switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
case 0:
base = 0xa0000;
size = 0x20000;
@@ -223,22 +237,20 @@ static void vga_precise_update_retrace_info(VGACommonState *s)
int64_t chars_per_sec;
struct vga_precise_retrace *r = &s->retrace_info.precise;
- htotal_chars = s->cr[0x00] + 5;
- hretr_start_char = s->cr[0x04];
- hretr_skew_chars = (s->cr[0x05] >> 5) & 3;
- hretr_end_char = s->cr[0x05] & 0x1f;
+ htotal_chars = s->cr[VGA_CRTC_H_TOTAL] + 5;
+ hretr_start_char = s->cr[VGA_CRTC_H_SYNC_START];
+ hretr_skew_chars = (s->cr[VGA_CRTC_H_SYNC_END] >> 5) & 3;
+ hretr_end_char = s->cr[VGA_CRTC_H_SYNC_END] & 0x1f;
- vtotal_lines = (s->cr[0x06]
- | (((s->cr[0x07] & 1) | ((s->cr[0x07] >> 4) & 2)) << 8)) + 2
- ;
- vretr_start_line = s->cr[0x10]
- | ((((s->cr[0x07] >> 2) & 1) | ((s->cr[0x07] >> 6) & 2)) << 8)
- ;
- vretr_end_line = s->cr[0x11] & 0xf;
+ vtotal_lines = (s->cr[VGA_CRTC_V_TOTAL] |
+ (((s->cr[VGA_CRTC_OVERFLOW] & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 4) & 2)) << 8)) + 2;
+ vretr_start_line = s->cr[VGA_CRTC_V_SYNC_START] |
+ ((((s->cr[VGA_CRTC_OVERFLOW] >> 2) & 1) |
+ ((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
+ vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
-
-
- clocking_mode = (s->sr[0x01] >> 3) & 1;
+ clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
clock_sel = (s->msr >> 2) & 3;
dots = (s->msr & 1) ? 8 : 9;
@@ -261,8 +273,8 @@ static void vga_precise_update_retrace_info(VGACommonState *s)
r->htotal = htotal_chars;
#if 0
- div2 = (s->cr[0x17] >> 2) & 1;
- sldiv2 = (s->cr[0x17] >> 3) & 1;
+ div2 = (s->cr[VGA_CRTC_MODE] >> 2) & 1;
+ sldiv2 = (s->cr[VGA_CRTC_MODE] >> 3) & 1;
printf (
"hz=%f\n"
"htotal = %d\n"
@@ -332,7 +344,7 @@ static uint8_t vga_dumb_retrace(VGACommonState *s)
int vga_ioport_invalid(VGACommonState *s, uint32_t addr)
{
- if (s->msr & MSR_COLOR_EMULATION) {
+ if (s->msr & VGA_MIS_COLOR) {
/* Color */
return (addr >= 0x3b0 && addr <= 0x3bf);
} else {
@@ -350,73 +362,74 @@ uint32_t vga_ioport_read(void *opaque, uint32_t addr)
val = 0xff;
} else {
switch(addr) {
- case 0x3c0:
+ case VGA_ATT_W:
if (s->ar_flip_flop == 0) {
val = s->ar_index;
} else {
val = 0;
}
break;
- case 0x3c1:
+ case VGA_ATT_R:
index = s->ar_index & 0x1f;
- if (index < 21)
+ if (index < VGA_ATT_C) {
val = s->ar[index];
- else
+ } else {
val = 0;
+ }
break;
- case 0x3c2:
+ case VGA_MIS_W:
val = s->st00;
break;
- case 0x3c4:
+ case VGA_SEQ_I:
val = s->sr_index;
break;
- case 0x3c5:
+ case VGA_SEQ_D:
val = s->sr[s->sr_index];
#ifdef DEBUG_VGA_REG
printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
#endif
break;
- case 0x3c7:
+ case VGA_PEL_IR:
val = s->dac_state;
break;
- case 0x3c8:
+ case VGA_PEL_IW:
val = s->dac_write_index;
break;
- case 0x3c9:
+ case VGA_PEL_D:
val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
if (++s->dac_sub_index == 3) {
s->dac_sub_index = 0;
s->dac_read_index++;
}
break;
- case 0x3ca:
+ case VGA_FTC_R:
val = s->fcr;
break;
- case 0x3cc:
+ case VGA_MIS_R:
val = s->msr;
break;
- case 0x3ce:
+ case VGA_GFX_I:
val = s->gr_index;
break;
- case 0x3cf:
+ case VGA_GFX_D:
val = s->gr[s->gr_index];
#ifdef DEBUG_VGA_REG
printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
#endif
break;
- case 0x3b4:
- case 0x3d4:
+ case VGA_CRT_IM:
+ case VGA_CRT_IC:
val = s->cr_index;
break;
- case 0x3b5:
- case 0x3d5:
+ case VGA_CRT_DM:
+ case VGA_CRT_DC:
val = s->cr[s->cr_index];
#ifdef DEBUG_VGA_REG
printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
#endif
break;
- case 0x3ba:
- case 0x3da:
+ case VGA_IS1_RM:
+ case VGA_IS1_RC:
/* just toggle to fool polling */
val = s->st01 = s->retrace(s);
s->ar_flip_flop = 0;
@@ -446,29 +459,29 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
#endif
switch(addr) {
- case 0x3c0:
+ case VGA_ATT_W:
if (s->ar_flip_flop == 0) {
val &= 0x3f;
s->ar_index = val;
} else {
index = s->ar_index & 0x1f;
switch(index) {
- case 0x00 ... 0x0f:
+ case VGA_ATC_PALETTE0 ... VGA_ATC_PALETTEF:
s->ar[index] = val & 0x3f;
break;
- case 0x10:
+ case VGA_ATC_MODE:
s->ar[index] = val & ~0x10;
break;
- case 0x11:
+ case VGA_ATC_OVERSCAN:
s->ar[index] = val;
break;
- case 0x12:
+ case VGA_ATC_PLANE_ENABLE:
s->ar[index] = val & ~0xc0;
break;
- case 0x13:
+ case VGA_ATC_PEL:
s->ar[index] = val & ~0xf0;
break;
- case 0x14:
+ case VGA_ATC_COLOR_PAGE:
s->ar[index] = val & ~0xf0;
break;
default:
@@ -477,32 +490,34 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
}
s->ar_flip_flop ^= 1;
break;
- case 0x3c2:
+ case VGA_MIS_W:
s->msr = val & ~0x10;
s->update_retrace_info(s);
break;
- case 0x3c4:
+ case VGA_SEQ_I:
s->sr_index = val & 7;
break;
- case 0x3c5:
+ case VGA_SEQ_D:
#ifdef DEBUG_VGA_REG
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
- if (s->sr_index == 1) s->update_retrace_info(s);
+ if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
+ s->update_retrace_info(s);
+ }
vga_update_memory_access(s);
break;
- case 0x3c7:
+ case VGA_PEL_IR:
s->dac_read_index = val;
s->dac_sub_index = 0;
s->dac_state = 3;
break;
- case 0x3c8:
+ case VGA_PEL_IW:
s->dac_write_index = val;
s->dac_sub_index = 0;
s->dac_state = 0;
break;
- case 0x3c9:
+ case VGA_PEL_D:
s->dac_cache[s->dac_sub_index] = val;
if (++s->dac_sub_index == 3) {
memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
@@ -510,48 +525,51 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->dac_write_index++;
}
break;
- case 0x3ce:
+ case VGA_GFX_I:
s->gr_index = val & 0x0f;
break;
- case 0x3cf:
+ case VGA_GFX_D:
#ifdef DEBUG_VGA_REG
printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
#endif
s->gr[s->gr_index] = val & gr_mask[s->gr_index];
vga_update_memory_access(s);
break;
- case 0x3b4:
- case 0x3d4:
+ case VGA_CRT_IM:
+ case VGA_CRT_IC:
s->cr_index = val;
break;
- case 0x3b5:
- case 0x3d5:
+ case VGA_CRT_DM:
+ case VGA_CRT_DC:
#ifdef DEBUG_VGA_REG
printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
#endif
/* handle CR0-7 protection */
- if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
+ if ((s->cr[VGA_CRTC_V_SYNC_END] & VGA_CR11_LOCK_CR0_CR7) &&
+ s->cr_index <= VGA_CRTC_OVERFLOW) {
/* can always write bit 4 of CR7 */
- if (s->cr_index == 7)
- s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
+ if (s->cr_index == VGA_CRTC_OVERFLOW) {
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x10) |
+ (val & 0x10);
+ }
return;
}
s->cr[s->cr_index] = val;
switch(s->cr_index) {
- case 0x00:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- case 0x11:
- case 0x17:
+ case VGA_CRTC_H_TOTAL:
+ case VGA_CRTC_H_SYNC_START:
+ case VGA_CRTC_H_SYNC_END:
+ case VGA_CRTC_V_TOTAL:
+ case VGA_CRTC_OVERFLOW:
+ case VGA_CRTC_V_SYNC_END:
+ case VGA_CRTC_MODE:
s->update_retrace_info(s);
break;
}
break;
- case 0x3ba:
- case 0x3da:
+ case VGA_IS1_RM:
+ case VGA_IS1_RC:
s->fcr = val & 0x10;
break;
}
@@ -681,31 +699,37 @@ static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
/* we initialize the VGA graphic mode (should be done
in BIOS) */
- s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
- s->cr[0x17] |= 3; /* no CGA modes */
- s->cr[0x13] = s->vbe_line_offset >> 3;
+ /* graphic mode + memory map 1 */
+ s->gr[VGA_GFX_MISC] = (s->gr[VGA_GFX_MISC] & ~0x0c) | 0x04 |
+ VGA_GR06_GRAPHICS_MODE;
+ s->cr[VGA_CRTC_MODE] |= 3; /* no CGA modes */
+ s->cr[VGA_CRTC_OFFSET] = s->vbe_line_offset >> 3;
/* width */
- s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
+ s->cr[VGA_CRTC_H_DISP] =
+ (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
/* height (only meaningful if < 1024) */
h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[0x12] = h;
- s->cr[0x07] = (s->cr[0x07] & ~0x42) |
+ s->cr[VGA_CRTC_V_DISP_END] = h;
+ s->cr[VGA_CRTC_OVERFLOW] = (s->cr[VGA_CRTC_OVERFLOW] & ~0x42) |
((h >> 7) & 0x02) | ((h >> 3) & 0x40);
/* line compare to 1023 */
- s->cr[0x18] = 0xff;
- s->cr[0x07] |= 0x10;
- s->cr[0x09] |= 0x40;
+ s->cr[VGA_CRTC_LINE_COMPARE] = 0xff;
+ s->cr[VGA_CRTC_OVERFLOW] |= 0x10;
+ s->cr[VGA_CRTC_MAX_SCAN] |= 0x40;
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
shift_control = 0;
- s->sr[0x01] &= ~8; /* no double line */
+ s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
} else {
shift_control = 2;
- s->sr[4] |= 0x08; /* set chain 4 mode */
- s->sr[2] |= 0x0f; /* activate all planes */
+ /* set chain 4 mode */
+ s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ /* activate all planes */
+ s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
}
- s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
- s->cr[0x09] &= ~0x9f; /* no double scan */
+ s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
+ (shift_control << 5);
+ s->cr[VGA_CRTC_MAX_SCAN] &= ~0x9f; /* no double scan */
} else {
/* XXX: the bios should do that */
s->bank_offset = 0;
@@ -762,7 +786,7 @@ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
uint32_t ret;
/* convert to VGA memory offset */
- memory_map_mode = (s->gr[6] >> 2) & 3;
+ memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
addr &= 0x1ffff;
switch(memory_map_mode) {
case 0:
@@ -785,24 +809,25 @@ uint32_t vga_mem_readb(VGACommonState *s, target_phys_addr_t addr)
break;
}
- if (s->sr[4] & 0x08) {
+ if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
ret = s->vram_ptr[addr];
- } else if (s->gr[5] & 0x10) {
+ } else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
- plane = (s->gr[4] & 2) | (addr & 1);
+ plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
ret = s->vram_ptr[((addr & ~1) << 1) | plane];
} else {
/* standard VGA latched access */
s->latch = ((uint32_t *)s->vram_ptr)[addr];
- if (!(s->gr[5] & 0x08)) {
+ if (!(s->gr[VGA_GFX_MODE] & 0x08)) {
/* read mode 0 */
- plane = s->gr[4];
+ plane = s->gr[VGA_GFX_PLANE_READ];
ret = GET_PLANE(s->latch, plane);
} else {
/* read mode 1 */
- ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
+ ret = (s->latch ^ mask16[s->gr[VGA_GFX_COMPARE_VALUE]]) &
+ mask16[s->gr[VGA_GFX_COMPARE_MASK]];
ret |= ret >> 16;
ret |= ret >> 8;
ret = (~ret) & 0xff;
@@ -821,7 +846,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);
#endif
/* convert to VGA memory offset */
- memory_map_mode = (s->gr[6] >> 2) & 3;
+ memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;
addr &= 0x1ffff;
switch(memory_map_mode) {
case 0:
@@ -844,67 +869,68 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
break;
}
- if (s->sr[4] & 0x08) {
+ if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
plane = addr & 3;
mask = (1 << plane);
- if (s->sr[2] & mask) {
+ if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
- memory_region_set_dirty(&s->vram, addr);
+ memory_region_set_dirty(&s->vram, addr, 1);
}
- } else if (s->gr[5] & 0x10) {
+ } else if (s->gr[VGA_GFX_MODE] & 0x10) {
/* odd/even mode (aka text mode mapping) */
- plane = (s->gr[4] & 2) | (addr & 1);
+ plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
mask = (1 << plane);
- if (s->sr[2] & mask) {
+ if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
addr = ((addr & ~1) << 1) | plane;
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);
#endif
s->plane_updated |= mask; /* only used to detect font change */
- memory_region_set_dirty(&s->vram, addr);
+ memory_region_set_dirty(&s->vram, addr, 1);
}
} else {
/* standard VGA latched access */
- write_mode = s->gr[5] & 3;
+ write_mode = s->gr[VGA_GFX_MODE] & 3;
switch(write_mode) {
default:
case 0:
/* rotate */
- b = s->gr[3] & 7;
+ b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
val = ((val >> b) | (val << (8 - b))) & 0xff;
val |= val << 8;
val |= val << 16;
/* apply set/reset mask */
- set_mask = mask16[s->gr[1]];
- val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
- bit_mask = s->gr[8];
+ set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];
+ val = (val & ~set_mask) |
+ (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);
+ bit_mask = s->gr[VGA_GFX_BIT_MASK];
break;
case 1:
val = s->latch;
goto do_write;
case 2:
val = mask16[val & 0x0f];
- bit_mask = s->gr[8];
+ bit_mask = s->gr[VGA_GFX_BIT_MASK];
break;
case 3:
/* rotate */
- b = s->gr[3] & 7;
+ b = s->gr[VGA_GFX_DATA_ROTATE] & 7;
val = (val >> b) | (val << (8 - b));
- bit_mask = s->gr[8] & val;
- val = mask16[s->gr[0]];
+ bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;
+ val = mask16[s->gr[VGA_GFX_SR_VALUE]];
break;
}
/* apply logical operation */
- func_select = s->gr[3] >> 3;
+ func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;
switch(func_select) {
case 0:
default:
@@ -931,7 +957,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
do_write:
/* mask data according to sr[2] */
- mask = s->sr[2];
+ mask = s->sr[VGA_SEQ_PLANE_WRITE];
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
((uint32_t *)s->vram_ptr)[addr] =
@@ -941,7 +967,7 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val)
printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",
addr * 4, write_mask, val);
#endif
- memory_region_set_dirty(&s->vram, addr << 2);
+ memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));
}
}
@@ -1045,10 +1071,11 @@ static int update_palette16(VGACommonState *s)
palette = s->last_palette;
for(i = 0; i < 16; i++) {
v = s->ar[i];
- if (s->ar[0x10] & 0x80)
- v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
- else
- v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
+ if (s->ar[VGA_ATC_MODE] & 0x80) {
+ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xf) << 4) | (v & 0xf);
+ } else {
+ v = ((s->ar[VGA_ATC_COLOR_PAGE] & 0xc) << 4) | (v & 0x3f);
+ }
v = v * 3;
col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
c6_to_8(s->palette[v + 1]),
@@ -1104,16 +1131,17 @@ static void vga_get_offsets(VGACommonState *s,
#endif
{
/* compute line_offset in bytes */
- line_offset = s->cr[0x13];
+ line_offset = s->cr[VGA_CRTC_OFFSET];
line_offset <<= 3;
/* starting address */
- start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
+ start_addr = s->cr[VGA_CRTC_START_LO] |
+ (s->cr[VGA_CRTC_START_HI] << 8);
/* line compare */
- line_compare = s->cr[0x18] |
- ((s->cr[0x07] & 0x10) << 4) |
- ((s->cr[0x09] & 0x40) << 3);
+ line_compare = s->cr[VGA_CRTC_LINE_COMPARE] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x10) << 4) |
+ ((s->cr[VGA_CRTC_MAX_SCAN] & 0x40) << 3);
}
*pline_offset = line_offset;
*pstart_addr = start_addr;
@@ -1216,20 +1244,22 @@ static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight
int width, cwidth, height, cheight;
/* total width & height */
- cheight = (s->cr[9] & 0x1f) + 1;
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cwidth = 8;
- if (!(s->sr[1] & 0x01))
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
cwidth = 9;
- if (s->sr[1] & 0x08)
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
cwidth = 16; /* NOTE: no 18 pixel wide */
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
/* ugly hack for CGA 160x100x16 - explain me the logic */
height = 100;
} else {
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
height = (height + 1) / cheight;
}
@@ -1273,7 +1303,7 @@ static void vga_draw_text(VGACommonState *s, int full_update)
vga_draw_glyph9_func *vga_draw_glyph9;
/* compute font data address (in plane 2) */
- v = s->sr[3];
+ v = s->sr[VGA_SEQ_CHARACTER_MAP];
offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
if (offset != s->font_offsets[0]) {
s->font_offsets[0] = offset;
@@ -1321,10 +1351,11 @@ static void vga_draw_text(VGACommonState *s, int full_update)
palette = s->last_palette;
x_incr = cw * ((ds_get_bits_per_pixel(s->ds) + 7) >> 3);
- cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
if (cursor_offset != s->cursor_offset ||
- s->cr[0xa] != s->cursor_start ||
- s->cr[0xb] != s->cursor_end) {
+ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end) {
/* if the cursor position changed, we update the old and new
chars */
if (s->cursor_offset < CH_ATTR_SIZE)
@@ -1332,8 +1363,8 @@ static void vga_draw_text(VGACommonState *s, int full_update)
if (cursor_offset < CH_ATTR_SIZE)
s->last_ch_attr[cursor_offset] = -1;
s->cursor_offset = cursor_offset;
- s->cursor_start = s->cr[0xa];
- s->cursor_end = s->cr[0xb];
+ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
}
cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
@@ -1378,17 +1409,19 @@ static void vga_draw_text(VGACommonState *s, int full_update)
font_ptr, cheight, fgcol, bgcol);
} else {
dup9 = 0;
- if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
+ if (ch >= 0xb0 && ch <= 0xdf &&
+ (s->ar[VGA_ATC_MODE] & 0x04)) {
dup9 = 1;
+ }
vga_draw_glyph9(d1, linesize,
font_ptr, cheight, fgcol, bgcol, dup9);
}
if (src == cursor_ptr &&
- !(s->cr[0x0a] & 0x20)) {
+ !(s->cr[VGA_CRTC_CURSOR_START] & 0x20)) {
int line_start, line_last, h;
/* draw the cursor */
- line_start = s->cr[0x0a] & 0x1f;
- line_last = s->cr[0x0b] & 0x1f;
+ line_start = s->cr[VGA_CRTC_CURSOR_START] & 0x1f;
+ line_last = s->cr[VGA_CRTC_CURSOR_END] & 0x1f;
/* XXX: check that */
if (line_last > cheight - 1)
line_last = cheight - 1;
@@ -1544,10 +1577,10 @@ static void vga_get_resolution(VGACommonState *s, int *pwidth, int *pheight)
} else
#endif
{
- width = (s->cr[0x01] + 1) * 8;
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
+ width = (s->cr[VGA_CRTC_H_DISP] + 1) * 8;
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
height = (height + 1);
}
*pwidth = width;
@@ -1602,10 +1635,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
s->get_resolution(s, &width, &height);
disp_width = width;
- shift_control = (s->gr[0x05] >> 5) & 3;
- double_scan = (s->cr[0x09] >> 7);
+ shift_control = (s->gr[VGA_GFX_MODE] >> 5) & 3;
+ double_scan = (s->cr[VGA_CRTC_MAX_SCAN] >> 7);
if (shift_control != 1) {
- multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
+ multi_scan = (((s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1) << double_scan)
+ - 1;
} else {
/* in CGA modes, multi_scan is ignored */
/* XXX: is it correct ? */
@@ -1620,11 +1654,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
}
if (shift_control == 0) {
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
disp_width <<= 1;
}
} else if (shift_control == 1) {
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
disp_width <<= 1;
}
}
@@ -1668,7 +1702,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (shift_control == 0) {
full_update |= update_palette16(s);
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
v = VGA_DRAW_LINE4D2;
} else {
v = VGA_DRAW_LINE4;
@@ -1676,7 +1710,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
bits = 4;
} else if (shift_control == 1) {
full_update |= update_palette16(s);
- if (s->sr[0x01] & 8) {
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
v = VGA_DRAW_LINE2D2;
} else {
v = VGA_DRAW_LINE2;
@@ -1721,7 +1755,8 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
line_offset = s->line_offset;
#if 0
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
- width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
+ width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
+ s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
#endif
addr1 = (s->start_addr * 4);
bwidth = (width * bits + 7) / 8;
@@ -1733,26 +1768,19 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
y1 = 0;
for(y = 0; y < height; y++) {
addr = addr1;
- if (!(s->cr[0x17] & 1)) {
+ if (!(s->cr[VGA_CRTC_MODE] & 1)) {
int shift;
/* CGA compatibility handling */
- shift = 14 + ((s->cr[0x17] >> 6) & 1);
+ shift = 14 + ((s->cr[VGA_CRTC_MODE] >> 6) & 1);
addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
}
- if (!(s->cr[0x17] & 2)) {
+ if (!(s->cr[VGA_CRTC_MODE] & 2)) {
addr = (addr & ~0x8000) | ((y1 & 2) << 14);
}
- page0 = addr & TARGET_PAGE_MASK;
- page1 = (addr + bwidth - 1) & TARGET_PAGE_MASK;
- update = full_update |
- memory_region_get_dirty(&s->vram, page0, DIRTY_MEMORY_VGA) |
- memory_region_get_dirty(&s->vram, page1, DIRTY_MEMORY_VGA);
- if ((page1 - page0) > TARGET_PAGE_SIZE) {
- /* if wide line, can use another page */
- update |= memory_region_get_dirty(&s->vram,
- page0 + TARGET_PAGE_SIZE,
- DIRTY_MEMORY_VGA);
- }
+ page0 = addr;
+ page1 = addr + bwidth - 1;
+ update = memory_region_get_dirty(&s->vram, page0, page1,
+ DIRTY_MEMORY_VGA);
/* explicit invalidation for the hardware cursor */
update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
if (update) {
@@ -1776,7 +1804,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
}
}
if (!multi_run) {
- mask = (s->cr[0x17] & 3) ^ 3;
+ mask = (s->cr[VGA_CRTC_MODE] & 3) ^ 3;
if ((y1 & mask) == mask)
addr1 += line_offset;
y1++;
@@ -1798,7 +1826,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (page_max >= page_min) {
memory_region_reset_dirty(&s->vram,
page_min,
- page_max + TARGET_PAGE_SIZE - page_min,
+ page_max - page_min,
DIRTY_MEMORY_VGA);
}
memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
@@ -1848,7 +1876,7 @@ static void vga_update_display(void *opaque)
if (!(s->ar_index & 0x20)) {
graphic_mode = GMODE_BLANK;
} else {
- graphic_mode = s->gr[6] & 1;
+ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
}
if (graphic_mode != s->graphic_mode) {
s->graphic_mode = graphic_mode;
@@ -1966,7 +1994,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
if (!(s->ar_index & 0x20)) {
graphic_mode = GMODE_BLANK;
} else {
- graphic_mode = s->gr[6] & 1;
+ graphic_mode = s->gr[VGA_GFX_MISC] & VGA_GR06_GRAPHICS_MODE;
}
if (graphic_mode != s->graphic_mode) {
s->graphic_mode = graphic_mode;
@@ -1983,20 +2011,22 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
full_update |= update_basic_params(s);
/* total width & height */
- cheight = (s->cr[9] & 0x1f) + 1;
+ cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cw = 8;
- if (!(s->sr[1] & 0x01))
+ if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
cw = 9;
- if (s->sr[1] & 0x08)
+ }
+ if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
cw = 16; /* NOTE: no 18 pixel wide */
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
+ }
+ width = (s->cr[VGA_CRTC_H_DISP] + 1);
+ if (s->cr[VGA_CRTC_V_TOTAL] == 100) {
/* ugly hack for CGA 160x100x16 - explain me the logic */
height = 100;
} else {
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
+ height = s->cr[VGA_CRTC_V_DISP_END] |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x02) << 7) |
+ ((s->cr[VGA_CRTC_OVERFLOW] & 0x40) << 3);
height = (height + 1) / cheight;
}
@@ -2025,11 +2055,12 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
}
/* Update "hardware" cursor */
- cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
+ cursor_offset = ((s->cr[VGA_CRTC_CURSOR_HI] << 8) |
+ s->cr[VGA_CRTC_CURSOR_LO]) - s->start_addr;
if (cursor_offset != s->cursor_offset ||
- s->cr[0xa] != s->cursor_start ||
- s->cr[0xb] != s->cursor_end || full_update) {
- cursor_visible = !(s->cr[0xa] & 0x20);
+ s->cr[VGA_CRTC_CURSOR_START] != s->cursor_start ||
+ s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
+ cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
dpy_cursor(s->ds,
TEXTMODE_X(cursor_offset),
@@ -2037,8 +2068,8 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
else
dpy_cursor(s->ds, -1, -1);
s->cursor_offset = cursor_offset;
- s->cursor_start = s->cr[0xa];
- s->cursor_end = s->cr[0xb];
+ s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
+ s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
}
src = (uint32_t *) s->vram_ptr + s->start_addr;
diff --git a/hw/vga.h b/hw/vga.h
new file mode 100644
index 0000000000..d917046da6
--- /dev/null
+++ b/hw/vga.h
@@ -0,0 +1,159 @@
+/*
+ * linux/include/video/vga.h -- standard VGA chipset interaction
+ *
+ * Copyright 1999 Jeff Garzik <jgarzik@pobox.com>
+ *
+ * Copyright history from vga16fb.c:
+ * Copyright 1999 Ben Pfaff and Petr Vandrovec
+ * Based on VGA info at http://www.osdever.net/FreeVGA/home.htm
+ * Based on VESA framebuffer (c) 1998 Gerd Knorr
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ */
+
+#ifndef __linux_video_vga_h__
+#define __linux_video_vga_h__
+
+/* Some of the code below is taken from SVGAlib. The original,
+ unmodified copyright notice for that code is below. */
+/* VGAlib version 1.2 - (c) 1993 Tommy Frandsen */
+/* */
+/* This library is free software; you can redistribute it and/or */
+/* modify it without any restrictions. This library is distributed */
+/* in the hope that it will be useful, but without any warranty. */
+
+/* Multi-chipset support Copyright 1993 Harm Hanemaayer */
+/* partially copyrighted (C) 1993 by Hartmut Schirmer */
+
+/* VGA data register ports */
+#define VGA_CRT_DC 0x3D5 /* CRT Controller Data Register - color emulation */
+#define VGA_CRT_DM 0x3B5 /* CRT Controller Data Register - mono emulation */
+#define VGA_ATT_R 0x3C1 /* Attribute Controller Data Read Register */
+#define VGA_ATT_W 0x3C0 /* Attribute Controller Data Write Register */
+#define VGA_GFX_D 0x3CF /* Graphics Controller Data Register */
+#define VGA_SEQ_D 0x3C5 /* Sequencer Data Register */
+#define VGA_MIS_R 0x3CC /* Misc Output Read Register */
+#define VGA_MIS_W 0x3C2 /* Misc Output Write Register */
+#define VGA_FTC_R 0x3CA /* Feature Control Read Register */
+#define VGA_IS1_RC 0x3DA /* Input Status Register 1 - color emulation */
+#define VGA_IS1_RM 0x3BA /* Input Status Register 1 - mono emulation */
+#define VGA_PEL_D 0x3C9 /* PEL Data Register */
+#define VGA_PEL_MSK 0x3C6 /* PEL mask register */
+
+/* EGA-specific registers */
+#define EGA_GFX_E0 0x3CC /* Graphics enable processor 0 */
+#define EGA_GFX_E1 0x3CA /* Graphics enable processor 1 */
+
+/* VGA index register ports */
+#define VGA_CRT_IC 0x3D4 /* CRT Controller Index - color emulation */
+#define VGA_CRT_IM 0x3B4 /* CRT Controller Index - mono emulation */
+#define VGA_ATT_IW 0x3C0 /* Attribute Controller Index & Data Write Register */
+#define VGA_GFX_I 0x3CE /* Graphics Controller Index */
+#define VGA_SEQ_I 0x3C4 /* Sequencer Index */
+#define VGA_PEL_IW 0x3C8 /* PEL Write Index */
+#define VGA_PEL_IR 0x3C7 /* PEL Read Index */
+
+/* standard VGA indexes max counts */
+#define VGA_CRT_C 0x19 /* Number of CRT Controller Registers */
+#define VGA_ATT_C 0x15 /* Number of Attribute Controller Registers */
+#define VGA_GFX_C 0x09 /* Number of Graphics Controller Registers */
+#define VGA_SEQ_C 0x05 /* Number of Sequencer Registers */
+#define VGA_MIS_C 0x01 /* Number of Misc Output Register */
+
+/* VGA misc register bit masks */
+#define VGA_MIS_COLOR 0x01
+#define VGA_MIS_ENB_MEM_ACCESS 0x02
+#define VGA_MIS_DCLK_28322_720 0x04
+#define VGA_MIS_ENB_PLL_LOAD (0x04 | 0x08)
+#define VGA_MIS_SEL_HIGH_PAGE 0x20
+
+/* VGA CRT controller register indices */
+#define VGA_CRTC_H_TOTAL 0
+#define VGA_CRTC_H_DISP 1
+#define VGA_CRTC_H_BLANK_START 2
+#define VGA_CRTC_H_BLANK_END 3
+#define VGA_CRTC_H_SYNC_START 4
+#define VGA_CRTC_H_SYNC_END 5
+#define VGA_CRTC_V_TOTAL 6
+#define VGA_CRTC_OVERFLOW 7
+#define VGA_CRTC_PRESET_ROW 8
+#define VGA_CRTC_MAX_SCAN 9
+#define VGA_CRTC_CURSOR_START 0x0A
+#define VGA_CRTC_CURSOR_END 0x0B
+#define VGA_CRTC_START_HI 0x0C
+#define VGA_CRTC_START_LO 0x0D
+#define VGA_CRTC_CURSOR_HI 0x0E
+#define VGA_CRTC_CURSOR_LO 0x0F
+#define VGA_CRTC_V_SYNC_START 0x10
+#define VGA_CRTC_V_SYNC_END 0x11
+#define VGA_CRTC_V_DISP_END 0x12
+#define VGA_CRTC_OFFSET 0x13
+#define VGA_CRTC_UNDERLINE 0x14
+#define VGA_CRTC_V_BLANK_START 0x15
+#define VGA_CRTC_V_BLANK_END 0x16
+#define VGA_CRTC_MODE 0x17
+#define VGA_CRTC_LINE_COMPARE 0x18
+#define VGA_CRTC_REGS VGA_CRT_C
+
+/* VGA CRT controller bit masks */
+#define VGA_CR11_LOCK_CR0_CR7 0x80 /* lock writes to CR0 - CR7 */
+#define VGA_CR17_H_V_SIGNALS_ENABLED 0x80
+
+/* VGA attribute controller register indices */
+#define VGA_ATC_PALETTE0 0x00
+#define VGA_ATC_PALETTE1 0x01
+#define VGA_ATC_PALETTE2 0x02
+#define VGA_ATC_PALETTE3 0x03
+#define VGA_ATC_PALETTE4 0x04
+#define VGA_ATC_PALETTE5 0x05
+#define VGA_ATC_PALETTE6 0x06
+#define VGA_ATC_PALETTE7 0x07
+#define VGA_ATC_PALETTE8 0x08
+#define VGA_ATC_PALETTE9 0x09
+#define VGA_ATC_PALETTEA 0x0A
+#define VGA_ATC_PALETTEB 0x0B
+#define VGA_ATC_PALETTEC 0x0C
+#define VGA_ATC_PALETTED 0x0D
+#define VGA_ATC_PALETTEE 0x0E
+#define VGA_ATC_PALETTEF 0x0F
+#define VGA_ATC_MODE 0x10
+#define VGA_ATC_OVERSCAN 0x11
+#define VGA_ATC_PLANE_ENABLE 0x12
+#define VGA_ATC_PEL 0x13
+#define VGA_ATC_COLOR_PAGE 0x14
+
+#define VGA_AR_ENABLE_DISPLAY 0x20
+
+/* VGA sequencer register indices */
+#define VGA_SEQ_RESET 0x00
+#define VGA_SEQ_CLOCK_MODE 0x01
+#define VGA_SEQ_PLANE_WRITE 0x02
+#define VGA_SEQ_CHARACTER_MAP 0x03
+#define VGA_SEQ_MEMORY_MODE 0x04
+
+/* VGA sequencer register bit masks */
+#define VGA_SR01_CHAR_CLK_8DOTS 0x01 /* bit 0: character clocks 8 dots wide are generated */
+#define VGA_SR01_SCREEN_OFF 0x20 /* bit 5: Screen is off */
+#define VGA_SR02_ALL_PLANES 0x0F /* bits 3-0: enable access to all planes */
+#define VGA_SR04_EXT_MEM 0x02 /* bit 1: allows complete mem access to 256K */
+#define VGA_SR04_SEQ_MODE 0x04 /* bit 2: directs system to use a sequential addressing mode */
+#define VGA_SR04_CHN_4M 0x08 /* bit 3: selects modulo 4 addressing for CPU access to display memory */
+
+/* VGA graphics controller register indices */
+#define VGA_GFX_SR_VALUE 0x00
+#define VGA_GFX_SR_ENABLE 0x01
+#define VGA_GFX_COMPARE_VALUE 0x02
+#define VGA_GFX_DATA_ROTATE 0x03
+#define VGA_GFX_PLANE_READ 0x04
+#define VGA_GFX_MODE 0x05
+#define VGA_GFX_MISC 0x06
+#define VGA_GFX_COMPARE_MASK 0x07
+#define VGA_GFX_BIT_MASK 0x08
+
+/* VGA graphics controller bit masks */
+#define VGA_GR06_GRAPHICS_MODE 0x01
+
+#endif /* __linux_video_vga_h__ */
diff --git a/hw/vga_int.h b/hw/vga_int.h
index c1e700fa0b..7685b2b167 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -25,9 +25,6 @@
#include <hw/hw.h>
#include "memory.h"
-#define MSR_COLOR_EMULATION 0x01
-#define MSR_PAGE_SELECT 0x20
-
#define ST01_V_RETRACE 0x08
#define ST01_DISP_ENABLE 0x01
@@ -205,19 +202,6 @@ void vga_mem_writeb(VGACommonState *s, target_phys_addr_t addr, uint32_t val);
void vga_invalidate_scanlines(VGACommonState *s, int y1, int y2);
int ppm_save(const char *filename, struct DisplaySurface *ds);
-void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-
int vga_ioport_invalid(VGACommonState *s, uint32_t addr);
void vga_init_vbe(VGACommonState *s, MemoryRegion *address_space);
diff --git a/hw/vga_template.h b/hw/vga_template.h
index 681425f9a2..f6f6a01d84 100644
--- a/hw/vga_template.h
+++ b/hw/vga_template.h
@@ -161,7 +161,7 @@ static void glue(vga_draw_line2_, DEPTH)(VGACommonState *s1, uint8_t *d,
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -203,7 +203,7 @@ static void glue(vga_draw_line2d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -236,7 +236,7 @@ static void glue(vga_draw_line4_, DEPTH)(VGACommonState *s1, uint8_t *d,
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -268,7 +268,7 @@ static void glue(vga_draw_line4d2_, DEPTH)(VGACommonState *s1, uint8_t *d,
int x;
palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
+ plane_mask = mask16[s1->ar[VGA_ATC_PLANE_ENABLE] & 0xf];
width >>= 3;
for(x = 0; x < width; x++) {
data = ((uint32_t *)s)[0];
@@ -340,72 +340,6 @@ static void glue(vga_draw_line8_, DEPTH)(VGACommonState *s1, uint8_t *d,
}
}
-void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
- const uint8_t *src1,
- int poffset, int w,
- unsigned int color0,
- unsigned int color1,
- unsigned int color_xor)
-{
- const uint8_t *plane0, *plane1;
- int x, b0, b1;
- uint8_t *d;
-
- d = d1;
- plane0 = src1;
- plane1 = src1 + poffset;
- for(x = 0; x < w; x++) {
- b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
- b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
-#if DEPTH == 8
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- d[0] ^= color_xor;
- break;
- case 2:
- d[0] = color0;
- break;
- case 3:
- d[0] = color1;
- break;
- }
-#elif DEPTH == 16
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint16_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint16_t *)d)[0] = color0;
- break;
- case 3:
- ((uint16_t *)d)[0] = color1;
- break;
- }
-#elif DEPTH == 32
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint32_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint32_t *)d)[0] = color0;
- break;
- case 3:
- ((uint32_t *)d)[0] = color1;
- break;
- }
-#else
-#error unsupported depth
-#endif
- d += BPP;
- }
-}
-
#endif /* DEPTH != 15 */
diff --git a/hw/vhost.c b/hw/vhost.c
index 4778521102..5ece659f4a 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -55,7 +55,7 @@ static void vhost_dev_sync_region(struct vhost_dev *dev,
ram_addr_t ram_addr;
bit -= 1;
ram_addr = section->offset_within_region + bit * VHOST_LOG_PAGE;
- memory_region_set_dirty(section->mr, ram_addr);
+ memory_region_set_dirty(section->mr, ram_addr, VHOST_LOG_PAGE);
log &= ~(0x1ull << bit);
}
addr += VHOST_LOG_CHUNK;
diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c
index bd16b97934..f8d2b1be04 100644
--- a/hw/virtex_ml507.c
+++ b/hw/virtex_ml507.c
@@ -38,7 +38,6 @@
#include "ppc.h"
#include "ppc4xx.h"
-#include "ppc440.h"
#include "ppc405.h"
#include "blockdev.h"
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index 5b416c36ee..a5a439668b 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -346,6 +346,8 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
bdrv_acct_start(req->dev->bs, &req->acct, req->qiov.size, BDRV_ACCT_READ);
+ trace_virtio_blk_handle_read(req, sector, req->qiov.size / 512);
+
if (sector & req->dev->sector_mask) {
virtio_blk_rw_complete(req, -EIO);
return;
diff --git a/hw/virtio-console.c b/hw/virtio-console.c
index 0b28a30b8c..4f2c3e4379 100644
--- a/hw/virtio-console.c
+++ b/hw/virtio-console.c
@@ -109,10 +109,9 @@ static void chr_event(void *opaque, int event)
static int virtconsole_initfn(VirtIOSerialPort *port)
{
VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
- VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
- vcon->port.dev.info);
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_GET_CLASS(port);
- if (port->id == 0 && !info->is_console) {
+ if (port->id == 0 && !k->is_console) {
error_report("Port number 0 on virtio-serial devices reserved for virtconsole devices for backward compatibility.");
return -1;
}
@@ -125,41 +124,63 @@ static int virtconsole_initfn(VirtIOSerialPort *port)
return 0;
}
-static VirtIOSerialPortInfo virtconsole_info = {
- .qdev.name = "virtconsole",
- .qdev.size = sizeof(VirtConsole),
- .is_console = true,
- .init = virtconsole_initfn,
- .have_data = flush_buf,
- .guest_open = guest_open,
- .guest_close = guest_close,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property virtconsole_properties[] = {
+ DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtconsole_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+ k->is_console = true;
+ k->init = virtconsole_initfn;
+ k->have_data = flush_buf;
+ k->guest_open = guest_open;
+ k->guest_close = guest_close;
+ dc->props = virtconsole_properties;
+}
+
+static TypeInfo virtconsole_info = {
+ .name = "virtconsole",
+ .parent = TYPE_VIRTIO_SERIAL_PORT,
+ .instance_size = sizeof(VirtConsole),
+ .class_init = virtconsole_class_init,
};
static void virtconsole_register(void)
{
- virtio_serial_port_qdev_register(&virtconsole_info);
+ type_register_static(&virtconsole_info);
}
device_init(virtconsole_register)
-static VirtIOSerialPortInfo virtserialport_info = {
- .qdev.name = "virtserialport",
- .qdev.size = sizeof(VirtConsole),
- .init = virtconsole_initfn,
- .have_data = flush_buf,
- .guest_open = guest_open,
- .guest_close = guest_close,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", VirtConsole, chr),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property virtserialport_properties[] = {
+ DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtserialport_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass);
+
+ k->init = virtconsole_initfn;
+ k->have_data = flush_buf;
+ k->guest_open = guest_open;
+ k->guest_close = guest_close;
+ dc->props = virtserialport_properties;
+}
+
+static TypeInfo virtserialport_info = {
+ .name = "virtserialport",
+ .parent = TYPE_VIRTIO_SERIAL_PORT,
+ .instance_size = sizeof(VirtConsole),
+ .class_init = virtserialport_class_init,
};
static void virtserialport_register(void)
{
- virtio_serial_port_qdev_register(&virtserialport_info);
+ type_register_static(&virtserialport_info);
}
device_init(virtserialport_register)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 8c2f460147..bc5e3a83d1 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -1030,7 +1030,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
memcpy(&n->mac[0], &conf->macaddr, sizeof(n->mac));
n->status = VIRTIO_NET_S_LINK_UP;
- n->nic = qemu_new_nic(&net_virtio_info, conf, dev->info->name, dev->id, n);
+ n->nic = qemu_new_nic(&net_virtio_info, conf, object_get_typename(OBJECT(dev)), dev->id, n);
qemu_format_nic_info_str(&n->nic->nc, conf->macaddr.a);
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index caff0aa2eb..93fff54782 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -91,6 +91,9 @@
*/
#define wmb() do { } while (0)
+/* HACK for virtio to determine if it's running a big endian guest */
+bool virtio_is_big_endian(void);
+
/* virtio device */
static void virtio_pci_notify(void *opaque, uint16_t vector)
@@ -414,20 +417,35 @@ static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr)
{
VirtIOPCIProxy *proxy = opaque;
uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+ uint16_t val;
if (addr < config)
return virtio_ioport_read(proxy, addr);
addr -= config;
- return virtio_config_readw(proxy->vdev, addr);
+ val = virtio_config_readw(proxy->vdev, addr);
+ if (virtio_is_big_endian()) {
+ /*
+ * virtio is odd, ioports are LE but config space is target native
+ * endian. However, in qemu, all PIO is LE, so we need to re-swap
+ * on BE targets
+ */
+ val = bswap16(val);
+ }
+ return val;
}
static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr)
{
VirtIOPCIProxy *proxy = opaque;
uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev);
+ uint32_t val;
if (addr < config)
return virtio_ioport_read(proxy, addr);
addr -= config;
- return virtio_config_readl(proxy->vdev, addr);
+ val = virtio_config_readl(proxy->vdev, addr);
+ if (virtio_is_big_endian()) {
+ val = bswap32(val);
+ }
+ return val;
}
static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val)
@@ -451,6 +469,9 @@ static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val)
return;
}
addr -= config;
+ if (virtio_is_big_endian()) {
+ val = bswap16(val);
+ }
virtio_config_writew(proxy->vdev, addr, val);
}
@@ -463,6 +484,9 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
return;
}
addr -= config;
+ if (virtio_is_big_endian()) {
+ val = bswap32(val);
+ }
virtio_config_writel(proxy->vdev, addr, val);
}
@@ -782,98 +806,136 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
return virtio_exit_pci(pci_dev);
}
-static PCIDeviceInfo virtio_info[] = {
- {
- .qdev.name = "virtio-blk-pci",
- .qdev.alias = "virtio-blk",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_blk_init_pci,
- .exit = virtio_blk_exit_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_BLOCK,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_STORAGE_SCSI,
- .qdev.props = (Property[]) {
- DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
- DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
- DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- .qdev.name = "virtio-net-pci",
- .qdev.alias = "virtio-net",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_net_init_pci,
- .exit = virtio_net_exit_pci,
- .romfile = "pxe-virtio.rom",
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_NET,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
- DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
- DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy,
- net.txtimer, TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy,
- net.txburst, TX_BURST),
- DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- .qdev.name = "virtio-serial-pci",
- .qdev.alias = "virtio-serial",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_serial_init_pci,
- .exit = virtio_serial_exit_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_COMMUNICATION_OTHER,
- .qdev.props = (Property[]) {
- DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
- VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
- DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
- DEV_NVECTORS_UNSPECIFIED),
- DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy,
- serial.max_virtserial_ports, 31),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- .qdev.name = "virtio-balloon-pci",
- .qdev.alias = "virtio-balloon",
- .qdev.size = sizeof(VirtIOPCIProxy),
- .init = virtio_balloon_init_pci,
- .exit = virtio_balloon_exit_pci,
- .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET,
- .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON,
- .revision = VIRTIO_PCI_ABI_VERSION,
- .class_id = PCI_CLASS_MEMORY_RAM,
- .qdev.props = (Property[]) {
- DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
- DEFINE_PROP_END_OF_LIST(),
- },
- .qdev.reset = virtio_pci_reset,
- },{
- /* end of list */
- }
+static Property virtio_blk_properties[] = {
+ DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
+ DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
+ DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_blk_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_blk_init_pci;
+ k->exit = virtio_blk_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_BLOCK;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_STORAGE_SCSI;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_blk_properties;
+}
+
+static TypeInfo virtio_blk_info = {
+ .name = "virtio-blk-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_blk_class_init,
+};
+
+static Property virtio_net_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 3),
+ DEFINE_VIRTIO_NET_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_NIC_PROPERTIES(VirtIOPCIProxy, nic),
+ DEFINE_PROP_UINT32("x-txtimer", VirtIOPCIProxy, net.txtimer, TX_TIMER_INTERVAL),
+ DEFINE_PROP_INT32("x-txburst", VirtIOPCIProxy, net.txburst, TX_BURST),
+ DEFINE_PROP_STRING("tx", VirtIOPCIProxy, net.tx),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_net_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_net_init_pci;
+ k->exit = virtio_net_exit_pci;
+ k->romfile = "pxe-virtio.rom";
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_NET;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_net_properties;
+}
+
+static TypeInfo virtio_net_info = {
+ .name = "virtio-net-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_net_class_init,
+};
+
+static Property virtio_serial_properties[] = {
+ DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, DEV_NVECTORS_UNSPECIFIED),
+ DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_UINT32("max_ports", VirtIOPCIProxy, serial.max_virtserial_ports, 31),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_serial_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_serial_init_pci;
+ k->exit = virtio_serial_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_CONSOLE;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_serial_properties;
+}
+
+static TypeInfo virtio_serial_info = {
+ .name = "virtio-serial-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_serial_class_init,
+};
+
+static Property virtio_balloon_properties[] = {
+ DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_balloon_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_balloon_init_pci;
+ k->exit = virtio_balloon_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_BALLOON;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_MEMORY_RAM;
+ dc->reset = virtio_pci_reset;
+ dc->props = virtio_balloon_properties;
+}
+
+static TypeInfo virtio_balloon_info = {
+ .name = "virtio-balloon-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_balloon_class_init,
};
static void virtio_pci_register_devices(void)
{
- pci_qdev_register_many(virtio_info);
+ type_register_static(&virtio_blk_info);
+ type_register_static(&virtio_net_info);
+ type_register_static(&virtio_serial_info);
+ type_register_static(&virtio_balloon_info);
}
device_init(virtio_pci_register_devices)
diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
index 32e46e98cb..61176299a3 100644
--- a/hw/virtio-serial-bus.c
+++ b/hw/virtio-serial-bus.c
@@ -133,12 +133,12 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev)
static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
VirtIODevice *vdev)
{
- VirtIOSerialPortInfo *info;
+ VirtIOSerialPortClass *vsc;
assert(port);
assert(virtio_queue_ready(vq));
- info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+ vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
while (!port->throttled) {
unsigned int i;
@@ -157,7 +157,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
ssize_t ret;
buf_size = port->elem.out_sg[i].iov_len - port->iov_offset;
- ret = info->have_data(port,
+ ret = vsc->have_data(port,
port->elem.out_sg[i].iov_base
+ port->iov_offset,
buf_size);
@@ -176,7 +176,7 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
* 1: chardevs can notify frondends
* 2: the guest driver does not spin in these cases
*/
- if (!info->is_console) {
+ if (!vsc->is_console) {
virtio_serial_throttle_port(port, true);
}
port->iov_idx = i;
@@ -331,7 +331,7 @@ void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
{
struct VirtIOSerialPort *port;
- struct VirtIOSerialPortInfo *info;
+ VirtIOSerialPortClass *vsc;
struct virtio_console_control cpkt, *gcpkt;
uint8_t *buffer;
size_t buffer_len;
@@ -373,7 +373,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
trace_virtio_serial_handle_control_message_port(port->id);
- info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info);
+ vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
switch(cpkt.event) {
case VIRTIO_CONSOLE_PORT_READY:
@@ -389,7 +389,7 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
* this port is a console port so that the guest can hook it
* up to hvc.
*/
- if (info->is_console) {
+ if (vsc->is_console) {
send_control_event(port, VIRTIO_CONSOLE_CONSOLE_PORT, 1);
}
@@ -418,21 +418,21 @@ static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
* initialised. If some app is interested in knowing about
* this event, let it know.
*/
- if (info->guest_ready) {
- info->guest_ready(port);
+ if (vsc->guest_ready) {
+ vsc->guest_ready(port);
}
break;
case VIRTIO_CONSOLE_PORT_OPEN:
port->guest_connected = cpkt.value;
- if (cpkt.value && info->guest_open) {
+ if (cpkt.value && vsc->guest_open) {
/* Send the guest opened notification if an app is interested */
- info->guest_open(port);
+ vsc->guest_open(port);
}
- if (!cpkt.value && info->guest_close) {
+ if (!cpkt.value && vsc->guest_close) {
/* Send the guest closed notification if an app is interested */
- info->guest_close(port);
+ vsc->guest_close(port);
}
break;
}
@@ -748,10 +748,10 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id)
send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
}
-static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+static int virtser_port_qdev_init(DeviceState *qdev)
{
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
- VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev, base);
+ VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
VirtIOSerialBus *bus = DO_UPCAST(VirtIOSerialBus, qbus, qdev->parent_bus);
int ret, max_nr_ports;
bool plugging_port0;
@@ -759,14 +759,14 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
port->vser = bus->vser;
port->bh = qemu_bh_new(flush_queued_data_bh, port);
- assert(info->have_data);
+ assert(vsc->have_data);
/*
* Is the first console port we're seeing? If so, put it up at
* location 0. This is done for backward compatibility (old
* kernel, new qemu).
*/
- plugging_port0 = info->is_console && !find_port_by_id(port->vser, 0);
+ plugging_port0 = vsc->is_console && !find_port_by_id(port->vser, 0);
if (find_port_by_id(port->vser, port->id)) {
error_report("virtio-serial-bus: A port already exists at id %u",
@@ -793,7 +793,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
return -1;
}
- ret = info->init(port);
+ ret = vsc->init(port);
if (ret) {
return ret;
}
@@ -823,8 +823,7 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
static int virtser_port_qdev_exit(DeviceState *qdev)
{
VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, qdev);
- VirtIOSerialPortInfo *info = DO_UPCAST(VirtIOSerialPortInfo, qdev,
- port->dev.info);
+ VirtIOSerialPortClass *vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port);
VirtIOSerial *vser = port->vser;
qemu_bh_delete(port->bh);
@@ -832,21 +831,12 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
QTAILQ_REMOVE(&vser->ports, port, next);
- if (info->exit) {
- info->exit(port);
+ if (vsc->exit) {
+ vsc->exit(port);
}
return 0;
}
-void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info)
-{
- info->qdev.init = virtser_port_qdev_init;
- info->qdev.bus_info = &virtser_bus_info;
- info->qdev.exit = virtser_port_qdev_exit;
- info->qdev.unplug = qdev_simple_unplug_cb;
- qdev_register(&info->qdev);
-}
-
VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf)
{
VirtIOSerial *vser;
@@ -940,3 +930,28 @@ void virtio_serial_exit(VirtIODevice *vdev)
virtio_cleanup(vdev);
}
+
+static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *k = DEVICE_CLASS(klass);
+ k->init = virtser_port_qdev_init;
+ k->bus_info = &virtser_bus_info;
+ k->exit = virtser_port_qdev_exit;
+ k->unplug = qdev_simple_unplug_cb;
+}
+
+static TypeInfo virtio_serial_port_type_info = {
+ .name = TYPE_VIRTIO_SERIAL_PORT,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(VirtIOSerialPort),
+ .abstract = true,
+ .class_size = sizeof(VirtIOSerialPortClass),
+ .class_init = virtio_serial_port_class_init,
+};
+
+static void virtio_serial_register_devices(void)
+{
+ type_register_static(&virtio_serial_port_type_info);
+}
+
+device_init(virtio_serial_register_devices);
diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
index ab138038c0..16e39820a2 100644
--- a/hw/virtio-serial.h
+++ b/hw/virtio-serial.h
@@ -62,10 +62,52 @@ struct virtio_serial_conf {
/* == In-qemu interface == */
+#define TYPE_VIRTIO_SERIAL_PORT "virtio-serial-port"
+#define VIRTIO_SERIAL_PORT(obj) \
+ OBJECT_CHECK(VirtIOSerialPort, (obj), TYPE_VIRTIO_SERIAL_PORT)
+#define VIRTIO_SERIAL_PORT_CLASS(klass) \
+ OBJECT_CLASS_CHECK(VirtIOSerialPortClass, (klass), TYPE_VIRTIO_SERIAL_PORT)
+#define VIRTIO_SERIAL_PORT_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(VirtIOSerialPortClass, (obj), TYPE_VIRTIO_SERIAL_PORT)
+
typedef struct VirtIOSerial VirtIOSerial;
typedef struct VirtIOSerialBus VirtIOSerialBus;
typedef struct VirtIOSerialPort VirtIOSerialPort;
-typedef struct VirtIOSerialPortInfo VirtIOSerialPortInfo;
+
+typedef struct VirtIOSerialPortClass {
+ DeviceClass parent_class;
+
+ /* Is this a device that binds with hvc in the guest? */
+ bool is_console;
+
+ /*
+ * The per-port (or per-app) init function that's called when a
+ * new device is found on the bus.
+ */
+ int (*init)(VirtIOSerialPort *port);
+ /*
+ * Per-port exit function that's called when a port gets
+ * hot-unplugged or removed.
+ */
+ int (*exit)(VirtIOSerialPort *port);
+
+ /* Callbacks for guest events */
+ /* Guest opened device. */
+ void (*guest_open)(VirtIOSerialPort *port);
+ /* Guest closed device. */
+ void (*guest_close)(VirtIOSerialPort *port);
+
+ /* Guest is now ready to accept data (virtqueues set up). */
+ void (*guest_ready)(VirtIOSerialPort *port);
+
+ /*
+ * Guest wrote some data to the port. This data is handed over to
+ * the app via this callback. The app can return a size less than
+ * 'len'. In this case, throttling will be enabled for this port.
+ */
+ ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
+ size_t len);
+} VirtIOSerialPortClass;
/*
* This is the state that's shared between all the ports. Some of the
@@ -131,50 +173,9 @@ struct VirtIOSerialPort {
bool throttled;
};
-struct VirtIOSerialPortInfo {
- DeviceInfo qdev;
-
- /* Is this a device that binds with hvc in the guest? */
- bool is_console;
-
- /*
- * The per-port (or per-app) init function that's called when a
- * new device is found on the bus.
- */
- int (*init)(VirtIOSerialPort *port);
- /*
- * Per-port exit function that's called when a port gets
- * hot-unplugged or removed.
- */
- int (*exit)(VirtIOSerialPort *port);
-
- /* Callbacks for guest events */
- /* Guest opened device. */
- void (*guest_open)(VirtIOSerialPort *port);
- /* Guest closed device. */
- void (*guest_close)(VirtIOSerialPort *port);
-
- /* Guest is now ready to accept data (virtqueues set up). */
- void (*guest_ready)(VirtIOSerialPort *port);
-
- /*
- * Guest wrote some data to the port. This data is handed over to
- * the app via this callback. The app can return a size less than
- * 'len'. In this case, throttling will be enabled for this port.
- */
- ssize_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf,
- size_t len);
-};
-
/* Interface to the virtio-serial bus */
/*
- * Individual ports/apps should call this function to register the port
- * with the virtio-serial bus
- */
-void virtio_serial_port_qdev_register(VirtIOSerialPortInfo *info);
-
-/*
* Open a connection to the port
* Returns 0 on success (always).
*/
diff --git a/hw/virtio.c b/hw/virtio.c
index 81ecc40b31..74cc038af9 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -539,7 +539,7 @@ uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr)
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
- memcpy(&val, vdev->config + addr, sizeof(val));
+ val = ldub_p(vdev->config + addr);
return val;
}
@@ -552,7 +552,7 @@ uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr)
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
- memcpy(&val, vdev->config + addr, sizeof(val));
+ val = lduw_p(vdev->config + addr);
return val;
}
@@ -565,7 +565,7 @@ uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr)
if (addr > (vdev->config_len - sizeof(val)))
return (uint32_t)-1;
- memcpy(&val, vdev->config + addr, sizeof(val));
+ val = ldl_p(vdev->config + addr);
return val;
}
@@ -576,7 +576,7 @@ void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data)
if (addr > (vdev->config_len - sizeof(val)))
return;
- memcpy(vdev->config + addr, &val, sizeof(val));
+ stb_p(vdev->config + addr, val);
if (vdev->set_config)
vdev->set_config(vdev, vdev->config);
@@ -589,7 +589,7 @@ void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data)
if (addr > (vdev->config_len - sizeof(val)))
return;
- memcpy(vdev->config + addr, &val, sizeof(val));
+ stw_p(vdev->config + addr, val);
if (vdev->set_config)
vdev->set_config(vdev, vdev->config);
@@ -602,7 +602,7 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data)
if (addr > (vdev->config_len - sizeof(val)))
return;
- memcpy(vdev->config + addr, &val, sizeof(val));
+ stl_p(vdev->config + addr, val);
if (vdev->set_config)
vdev->set_config(vdev, vdev->config);
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
index 1113f33d68..fda4f89a76 100644
--- a/hw/vmmouse.c
+++ b/hw/vmmouse.c
@@ -254,6 +254,8 @@ static void vmmouse_reset(DeviceState *d)
s->status = 0xffff;
s->queue_size = VMMOUSE_QUEUE_SIZE;
+
+ vmmouse_disable(s);
}
static int vmmouse_initfn(ISADevice *dev)
@@ -269,21 +271,31 @@ static int vmmouse_initfn(ISADevice *dev)
return 0;
}
-static ISADeviceInfo vmmouse_info = {
- .init = vmmouse_initfn,
- .qdev.name = "vmmouse",
- .qdev.size = sizeof(VMMouseState),
- .qdev.vmsd = &vmstate_vmmouse,
- .qdev.no_user = 1,
- .qdev.reset = vmmouse_reset,
- .qdev.props = (Property[]) {
- DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property vmmouse_properties[] = {
+ DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vmmouse_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = vmmouse_initfn;
+ dc->no_user = 1;
+ dc->reset = vmmouse_reset;
+ dc->vmsd = &vmstate_vmmouse;
+ dc->props = vmmouse_properties;
+}
+
+static TypeInfo vmmouse_info = {
+ .name = "vmmouse",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(VMMouseState),
+ .class_init = vmmouse_class_initfn,
};
static void vmmouse_dev_register(void)
{
- isa_qdev_register(&vmmouse_info);
+ type_register_static(&vmmouse_info);
}
device_init(vmmouse_dev_register)
diff --git a/hw/vmport.c b/hw/vmport.c
index 0a3dbc5ef5..a2c45e1950 100644
--- a/hw/vmport.c
+++ b/hw/vmport.c
@@ -144,15 +144,23 @@ static int vmport_initfn(ISADevice *dev)
return 0;
}
-static ISADeviceInfo vmport_info = {
- .qdev.name = "vmport",
- .qdev.size = sizeof(VMPortState),
- .qdev.no_user = 1,
- .init = vmport_initfn,
+static void vmport_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = vmport_initfn;
+ dc->no_user = 1;
+}
+
+static TypeInfo vmport_info = {
+ .name = "vmport",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(VMPortState),
+ .class_init = vmport_class_initfn,
};
static void vmport_dev_register(void)
{
- isa_qdev_register(&vmport_info);
+ type_register_static(&vmport_info);
}
device_init(vmport_dev_register)
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index b1885c3c19..3f3eb21d02 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1199,24 +1199,32 @@ static int pci_vmsvga_initfn(PCIDevice *dev)
return 0;
}
-static PCIDeviceInfo vmsvga_info = {
- .qdev.name = "vmware-svga",
- .qdev.size = sizeof(struct pci_vmsvga_state_s),
- .qdev.vmsd = &vmstate_vmware_vga,
- .qdev.reset = vmsvga_reset,
- .no_hotplug = 1,
- .init = pci_vmsvga_initfn,
- .romfile = "vgabios-vmware.bin",
-
- .vendor_id = PCI_VENDOR_ID_VMWARE,
- .device_id = SVGA_PCI_DEVICE_ID,
- .class_id = PCI_CLASS_DISPLAY_VGA,
- .subsystem_vendor_id = PCI_VENDOR_ID_VMWARE,
- .subsystem_id = SVGA_PCI_DEVICE_ID,
+static void vmsvga_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->no_hotplug = 1;
+ k->init = pci_vmsvga_initfn;
+ k->romfile = "vgabios-vmware.bin";
+ k->vendor_id = PCI_VENDOR_ID_VMWARE;
+ k->device_id = SVGA_PCI_DEVICE_ID;
+ k->class_id = PCI_CLASS_DISPLAY_VGA;
+ k->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE;
+ k->subsystem_id = SVGA_PCI_DEVICE_ID;
+ dc->reset = vmsvga_reset;
+ dc->vmsd = &vmstate_vmware_vga;
+}
+
+static TypeInfo vmsvga_info = {
+ .name = "vmware-svga",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(struct pci_vmsvga_state_s),
+ .class_init = vmsvga_class_init,
};
static void vmsvga_register(void)
{
- pci_qdev_register(&vmsvga_info);
+ type_register_static(&vmsvga_info);
}
device_init(vmsvga_register);
diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h
index db11cbfac8..000fbddc0f 100644
--- a/hw/vmware_vga.h
+++ b/hw/vmware_vga.h
@@ -8,12 +8,8 @@ static inline DeviceState *pci_vmsvga_init(PCIBus *bus)
{
PCIDevice *dev;
- dev = pci_try_create(bus, -1, "vmware-svga");
- if (!dev || qdev_init(&dev->qdev) < 0) {
- return NULL;
- } else {
- return &dev->qdev;
- }
+ dev = pci_create_simple(bus, -1, "vmware-svga");
+ return &dev->qdev;
}
#endif
diff --git a/hw/vt82c686.c b/hw/vt82c686.c
index 7fb88a53bf..aa0954f487 100644
--- a/hw/vt82c686.c
+++ b/hw/vt82c686.c
@@ -346,20 +346,29 @@ void vt82c686b_ac97_init(PCIBus *bus, int devfn)
qdev_init_nofail(&dev->qdev);
}
-static PCIDeviceInfo via_ac97_info = {
- .qdev.name = "VT82C686B_AC97",
- .qdev.desc = "AC97",
- .qdev.size = sizeof(VT686AC97State),
- .init = vt82c686b_ac97_initfn,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_AC97,
- .revision = 0x50,
- .class_id = PCI_CLASS_MULTIMEDIA_AUDIO,
+static void via_ac97_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_ac97_initfn;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_AC97;
+ k->revision = 0x50;
+ k->class_id = PCI_CLASS_MULTIMEDIA_AUDIO;
+ dc->desc = "AC97";
+}
+
+static TypeInfo via_ac97_info = {
+ .name = "VT82C686B_AC97",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT686AC97State),
+ .class_init = via_ac97_class_init,
};
static void vt82c686b_ac97_register(void)
{
- pci_qdev_register(&via_ac97_info);
+ type_register_static(&via_ac97_info);
}
device_init(vt82c686b_ac97_register);
@@ -385,20 +394,29 @@ void vt82c686b_mc97_init(PCIBus *bus, int devfn)
qdev_init_nofail(&dev->qdev);
}
-static PCIDeviceInfo via_mc97_info = {
- .qdev.name = "VT82C686B_MC97",
- .qdev.desc = "MC97",
- .qdev.size = sizeof(VT686MC97State),
- .init = vt82c686b_mc97_initfn,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_MC97,
- .class_id = PCI_CLASS_COMMUNICATION_OTHER,
- .revision = 0x30,
+static void via_mc97_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_mc97_initfn;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_MC97;
+ k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
+ k->revision = 0x30;
+ dc->desc = "MC97";
+}
+
+static TypeInfo via_mc97_info = {
+ .name = "VT82C686B_MC97",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT686MC97State),
+ .class_init = via_mc97_class_init,
};
static void vt82c686b_mc97_register(void)
{
- pci_qdev_register(&via_mc97_info);
+ type_register_static(&via_mc97_info);
}
device_init(vt82c686b_mc97_register);
@@ -451,26 +469,37 @@ i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
return s->smb.smbus;
}
-static PCIDeviceInfo via_pm_info = {
- .qdev.name = "VT82C686B_PM",
- .qdev.desc = "PM",
- .qdev.size = sizeof(VT686PMState),
- .qdev.vmsd = &vmstate_acpi,
- .init = vt82c686b_pm_initfn,
- .config_write = pm_write_config,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_ACPI,
- .class_id = PCI_CLASS_BRIDGE_OTHER,
- .revision = 0x40,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property via_pm_properties[] = {
+ DEFINE_PROP_UINT32("smb_io_base", VT686PMState, smb_io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void via_pm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_pm_initfn;
+ k->config_write = pm_write_config;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_ACPI;
+ k->class_id = PCI_CLASS_BRIDGE_OTHER;
+ k->revision = 0x40;
+ dc->desc = "PM";
+ dc->vmsd = &vmstate_acpi;
+ dc->props = via_pm_properties;
+}
+
+static TypeInfo via_pm_info = {
+ .name = "VT82C686B_PM",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT686PMState),
+ .class_init = via_pm_class_init,
};
static void vt82c686b_pm_register(void)
{
- pci_qdev_register(&via_pm_info);
+ type_register_static(&via_pm_info);
}
device_init(vt82c686b_pm_register);
@@ -519,22 +548,31 @@ ISABus *vt82c686b_init(PCIBus *bus, int devfn)
return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0"));
}
-static PCIDeviceInfo via_info = {
- .qdev.name = "VT82C686B",
- .qdev.desc = "ISA bridge",
- .qdev.size = sizeof(VT82C686BState),
- .qdev.vmsd = &vmstate_via,
- .qdev.no_user = 1,
- .init = vt82c686b_initfn,
- .config_write = vt82c686b_write_config,
- .vendor_id = PCI_VENDOR_ID_VIA,
- .device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE,
- .class_id = PCI_CLASS_BRIDGE_ISA,
- .revision = 0x40,
+static void via_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = vt82c686b_initfn;
+ k->config_write = vt82c686b_write_config;
+ k->vendor_id = PCI_VENDOR_ID_VIA;
+ k->device_id = PCI_DEVICE_ID_VIA_ISA_BRIDGE;
+ k->class_id = PCI_CLASS_BRIDGE_ISA;
+ k->revision = 0x40;
+ dc->desc = "ISA bridge";
+ dc->no_user = 1;
+ dc->vmsd = &vmstate_via;
+}
+
+static TypeInfo via_info = {
+ .name = "VT82C686B",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VT82C686BState),
+ .class_init = via_class_init,
};
static void vt82c686b_register(void)
{
- pci_qdev_register(&via_info);
+ type_register_static(&via_info);
}
device_init(vt82c686b_register);
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 20d8673186..41325f0955 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -143,7 +143,7 @@ static void i6300esb_disable_timer(I6300State *d)
static void i6300esb_reset(DeviceState *dev)
{
- PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, dev);
+ PCIDevice *pdev = PCI_DEVICE(dev);
I6300State *d = DO_UPCAST(I6300State, dev, pdev);
i6300esb_debug("I6300State = %p\n", d);
@@ -425,24 +425,33 @@ static WatchdogTimerModel model = {
.wdt_description = "Intel 6300ESB",
};
-static PCIDeviceInfo i6300esb_info = {
- .qdev.name = "i6300esb",
- .qdev.size = sizeof(I6300State),
- .qdev.vmsd = &vmstate_i6300esb,
- .qdev.reset = i6300esb_reset,
- .config_read = i6300esb_config_read,
- .config_write = i6300esb_config_write,
- .init = i6300esb_init,
- .exit = i6300esb_exit,
- .vendor_id = PCI_VENDOR_ID_INTEL,
- .device_id = PCI_DEVICE_ID_INTEL_ESB_9,
- .class_id = PCI_CLASS_SYSTEM_OTHER,
+static void i6300esb_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->config_read = i6300esb_config_read;
+ k->config_write = i6300esb_config_write;
+ k->init = i6300esb_init;
+ k->exit = i6300esb_exit;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_ESB_9;
+ k->class_id = PCI_CLASS_SYSTEM_OTHER;
+ dc->reset = i6300esb_reset;
+ dc->vmsd = &vmstate_i6300esb;
+}
+
+static TypeInfo i6300esb_info = {
+ .name = "i6300esb",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(I6300State),
+ .class_init = i6300esb_class_init,
};
static void i6300esb_register_devices(void)
{
watchdog_add_model(&model);
- pci_qdev_register(&i6300esb_info);
+ type_register_static(&i6300esb_info);
}
device_init(i6300esb_register_devices);
diff --git a/hw/wdt_ib700.c b/hw/wdt_ib700.c
index ba1d92d615..8faa2316c9 100644
--- a/hw/wdt_ib700.c
+++ b/hw/wdt_ib700.c
@@ -120,18 +120,26 @@ static WatchdogTimerModel model = {
.wdt_description = "iBASE 700",
};
-static ISADeviceInfo wdt_ib700_info = {
- .qdev.name = "ib700",
- .qdev.size = sizeof(IB700State),
- .qdev.vmsd = &vmstate_ib700,
- .qdev.reset = wdt_ib700_reset,
- .init = wdt_ib700_init,
+static void wdt_ib700_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ ISADeviceClass *ic = ISA_DEVICE_CLASS(klass);
+ ic->init = wdt_ib700_init;
+ dc->reset = wdt_ib700_reset;
+ dc->vmsd = &vmstate_ib700;
+}
+
+static TypeInfo wdt_ib700_info = {
+ .name = "ib700",
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(IB700State),
+ .class_init = wdt_ib700_class_init,
};
static void wdt_ib700_register_devices(void)
{
watchdog_add_model(&model);
- isa_qdev_register(&wdt_ib700_info);
+ type_register_static(&wdt_ib700_info);
}
device_init(wdt_ib700_register_devices);
diff --git a/hw/wm8750.c b/hw/wm8750.c
index 9fbdf3d54b..18afa4c1ac 100644
--- a/hw/wm8750.c
+++ b/hw/wm8750.c
@@ -24,7 +24,7 @@ typedef struct {
} WMRate;
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
uint8_t i2c_data[2];
int i2c_len;
QEMUSoundCard card;
@@ -254,7 +254,7 @@ static void wm8750_clk_update(WM8750State *s, int ext)
}
}
-static void wm8750_reset(i2c_slave *i2c)
+static void wm8750_reset(I2CSlave *i2c)
{
WM8750State *s = (WM8750State *) i2c;
s->rate = &wm_rate_table[0];
@@ -297,7 +297,7 @@ static void wm8750_reset(i2c_slave *i2c)
s->i2c_len = 0;
}
-static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
+static void wm8750_event(I2CSlave *i2c, enum i2c_event event)
{
WM8750State *s = (WM8750State *) i2c;
@@ -354,7 +354,7 @@ static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
#define WM8750_ROUT2V 0x29
#define WM8750_MOUTV 0x2a
-static int wm8750_tx(i2c_slave *i2c, uint8_t data)
+static int wm8750_tx(I2CSlave *i2c, uint8_t data)
{
WM8750State *s = (WM8750State *) i2c;
uint8_t cmd;
@@ -554,7 +554,7 @@ static int wm8750_tx(i2c_slave *i2c, uint8_t data)
return 0;
}
-static int wm8750_rx(i2c_slave *i2c)
+static int wm8750_rx(I2CSlave *i2c)
{
return 0x00;
}
@@ -609,7 +609,7 @@ static const VMStateDescription vmstate_wm8750 = {
}
};
-static int wm8750_init(i2c_slave *i2c)
+static int wm8750_init(I2CSlave *i2c)
{
WM8750State *s = FROM_I2C_SLAVE(WM8750State, i2c);
@@ -620,7 +620,7 @@ static int wm8750_init(i2c_slave *i2c)
}
#if 0
-static void wm8750_fini(i2c_slave *i2c)
+static void wm8750_fini(I2CSlave *i2c)
{
WM8750State *s = (WM8750State *) i2c;
wm8750_reset(&s->i2c);
@@ -689,19 +689,28 @@ void wm8750_set_bclk_in(void *opaque, int new_hz)
wm8750_clk_update(s, 1);
}
-static I2CSlaveInfo wm8750_info = {
- .qdev.name = "wm8750",
- .qdev.size = sizeof(WM8750State),
- .qdev.vmsd = &vmstate_wm8750,
- .init = wm8750_init,
- .event = wm8750_event,
- .recv = wm8750_rx,
- .send = wm8750_tx
+static void wm8750_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
+
+ sc->init = wm8750_init;
+ sc->event = wm8750_event;
+ sc->recv = wm8750_rx;
+ sc->send = wm8750_tx;
+ dc->vmsd = &vmstate_wm8750;
+}
+
+static TypeInfo wm8750_info = {
+ .name = "wm8750",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(WM8750State),
+ .class_init = wm8750_class_init,
};
static void wm8750_register_devices(void)
{
- i2c_register_slave(&wm8750_info);
+ type_register_static(&wm8750_info);
}
device_init(wm8750_register_devices)
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index e62eaef7d1..e7571022e4 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -372,25 +372,33 @@ static void platform_reset(DeviceState *dev)
platform_fixed_ioport_reset(s);
}
-static PCIDeviceInfo xen_platform_info = {
- .init = xen_platform_initfn,
- .qdev.name = "xen-platform",
- .qdev.desc = "XEN platform pci device",
- .qdev.size = sizeof(PCIXenPlatformState),
- .qdev.vmsd = &vmstate_xen_platform,
- .qdev.reset = platform_reset,
-
- .vendor_id = PCI_VENDOR_ID_XEN,
- .device_id = PCI_DEVICE_ID_XEN_PLATFORM,
- .class_id = PCI_CLASS_OTHERS << 8 | 0x80,
- .subsystem_vendor_id = PCI_VENDOR_ID_XEN,
- .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM,
- .revision = 1,
+static void xen_platform_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = xen_platform_initfn;
+ k->vendor_id = PCI_VENDOR_ID_XEN;
+ k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
+ k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
+ k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
+ k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
+ k->revision = 1;
+ dc->desc = "XEN platform pci device";
+ dc->reset = platform_reset;
+ dc->vmsd = &vmstate_xen_platform;
+}
+
+static TypeInfo xen_platform_info = {
+ .name = "xen-platform",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIXenPlatformState),
+ .class_init = xen_platform_class_init,
};
static void xen_platform_register(void)
{
- pci_qdev_register(&xen_platform_info);
+ type_register_static(&xen_platform_info);
}
device_init(xen_platform_register);
diff --git a/hw/xgmac.c b/hw/xgmac.c
new file mode 100644
index 0000000000..d395b1cc2d
--- /dev/null
+++ b/hw/xgmac.c
@@ -0,0 +1,433 @@
+/*
+ * QEMU model of XGMAC Ethernet.
+ *
+ * derived from the Xilinx AXI-Ethernet by Edgar E. Iglesias.
+ *
+ * Copyright (c) 2011 Calxeda, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "sysbus.h"
+#include "qemu-char.h"
+#include "qemu-log.h"
+#include "net.h"
+#include "net/checksum.h"
+
+#ifdef DEBUG_XGMAC
+#define DEBUGF_BRK(message, args...) do { \
+ fprintf(stderr, (message), ## args); \
+ } while (0)
+#else
+#define DEBUGF_BRK(message, args...) do { } while (0)
+#endif
+
+#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */
+#define XGMAC_FRAME_FILTER 0x00000001 /* MAC Frame Filter */
+#define XGMAC_FLOW_CTRL 0x00000006 /* MAC Flow Control */
+#define XGMAC_VLAN_TAG 0x00000007 /* VLAN Tags */
+#define XGMAC_VERSION 0x00000008 /* Version */
+/* VLAN tag for insertion or replacement into tx frames */
+#define XGMAC_VLAN_INCL 0x00000009
+#define XGMAC_LPI_CTRL 0x0000000a /* LPI Control and Status */
+#define XGMAC_LPI_TIMER 0x0000000b /* LPI Timers Control */
+#define XGMAC_TX_PACE 0x0000000c /* Transmit Pace and Stretch */
+#define XGMAC_VLAN_HASH 0x0000000d /* VLAN Hash Table */
+#define XGMAC_DEBUG 0x0000000e /* Debug */
+#define XGMAC_INT_STATUS 0x0000000f /* Interrupt and Control */
+/* HASH table registers */
+#define XGMAC_HASH(n) ((0x00000300/4) + (n))
+#define XGMAC_NUM_HASH 16
+/* Operation Mode */
+#define XGMAC_OPMODE (0x00000400/4)
+/* Remote Wake-Up Frame Filter */
+#define XGMAC_REMOTE_WAKE (0x00000700/4)
+/* PMT Control and Status */
+#define XGMAC_PMT (0x00000704/4)
+
+#define XGMAC_ADDR_HIGH(reg) (0x00000010+((reg) * 2))
+#define XGMAC_ADDR_LOW(reg) (0x00000011+((reg) * 2))
+
+#define DMA_BUS_MODE 0x000003c0 /* Bus Mode */
+#define DMA_XMT_POLL_DEMAND 0x000003c1 /* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND 0x000003c2 /* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR 0x000003c3 /* Receive List Base */
+#define DMA_TX_BASE_ADDR 0x000003c4 /* Transmit List Base */
+#define DMA_STATUS 0x000003c5 /* Status Register */
+#define DMA_CONTROL 0x000003c6 /* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA 0x000003c7 /* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR 0x000003c8 /* Missed Frame Counter */
+/* Receive Interrupt Watchdog Timer */
+#define DMA_RI_WATCHDOG_TIMER 0x000003c9
+#define DMA_AXI_BUS 0x000003ca /* AXI Bus Mode */
+#define DMA_AXI_STATUS 0x000003cb /* AXI Status */
+#define DMA_CUR_TX_DESC_ADDR 0x000003d2 /* Current Host Tx Descriptor */
+#define DMA_CUR_RX_DESC_ADDR 0x000003d3 /* Current Host Rx Descriptor */
+#define DMA_CUR_TX_BUF_ADDR 0x000003d4 /* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR 0x000003d5 /* Current Host Rx Buffer */
+#define DMA_HW_FEATURE 0x000003d6 /* Enabled Hardware Features */
+
+/* DMA Status register defines */
+#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
+#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
+#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT 20
+#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
+#define DMA_STATUS_RS_SHIFT 17
+#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
+#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
+#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
+#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
+#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
+#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
+#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
+#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
+#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
+#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
+#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
+#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
+#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
+
+/* DMA Control register defines */
+#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
+#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
+#define DMA_CONTROL_DFF 0x01000000 /* Disable flush of rx frames */
+
+struct desc {
+ uint32_t ctl_stat;
+ uint16_t buffer1_size;
+ uint16_t buffer2_size;
+ uint32_t buffer1_addr;
+ uint32_t buffer2_addr;
+ uint32_t ext_stat;
+ uint32_t res[3];
+};
+
+#define R_MAX 0x400
+
+typedef struct RxTxStats {
+ uint64_t rx_bytes;
+ uint64_t tx_bytes;
+
+ uint64_t rx;
+ uint64_t rx_bcast;
+ uint64_t rx_mcast;
+} RxTxStats;
+
+typedef struct XgmacState {
+ SysBusDevice busdev;
+ MemoryRegion iomem;
+ qemu_irq sbd_irq;
+ qemu_irq pmt_irq;
+ qemu_irq mci_irq;
+ NICState *nic;
+ NICConf conf;
+
+ struct RxTxStats stats;
+ uint32_t regs[R_MAX];
+} XgmacState;
+
+const VMStateDescription vmstate_rxtx_stats = {
+ .name = "xgmac_stats",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT64(rx_bytes, RxTxStats),
+ VMSTATE_UINT64(tx_bytes, RxTxStats),
+ VMSTATE_UINT64(rx, RxTxStats),
+ VMSTATE_UINT64(rx_bcast, RxTxStats),
+ VMSTATE_UINT64(rx_mcast, RxTxStats),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_xgmac = {
+ .name = "xgmac",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(stats, XgmacState, 0, vmstate_rxtx_stats, RxTxStats),
+ VMSTATE_UINT32_ARRAY(regs, XgmacState, R_MAX),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void xgmac_read_desc(struct XgmacState *s, struct desc *d, int rx)
+{
+ uint32_t addr = rx ? s->regs[DMA_CUR_RX_DESC_ADDR] :
+ s->regs[DMA_CUR_TX_DESC_ADDR];
+ cpu_physical_memory_read(addr, d, sizeof(*d));
+}
+
+static void xgmac_write_desc(struct XgmacState *s, struct desc *d, int rx)
+{
+ int reg = rx ? DMA_CUR_RX_DESC_ADDR : DMA_CUR_TX_DESC_ADDR;
+ uint32_t addr = s->regs[reg];
+
+ if (!rx && (d->ctl_stat & 0x00200000)) {
+ s->regs[reg] = s->regs[DMA_TX_BASE_ADDR];
+ } else if (rx && (d->buffer1_size & 0x8000)) {
+ s->regs[reg] = s->regs[DMA_RCV_BASE_ADDR];
+ } else {
+ s->regs[reg] += sizeof(*d);
+ }
+ cpu_physical_memory_write(addr, d, sizeof(*d));
+}
+
+static void xgmac_enet_send(struct XgmacState *s)
+{
+ struct desc bd;
+ int frame_size;
+ int len;
+ uint8_t frame[8192];
+ uint8_t *ptr;
+
+ ptr = frame;
+ frame_size = 0;
+ while (1) {
+ xgmac_read_desc(s, &bd, 0);
+ if ((bd.ctl_stat & 0x80000000) == 0) {
+ /* Run out of descriptors to transmit. */
+ break;
+ }
+ len = (bd.buffer1_size & 0xfff) + (bd.buffer2_size & 0xfff);
+
+ if ((bd.buffer1_size & 0xfff) > 2048) {
+ DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+ "xgmac buffer 1 len on send > 2048 (0x%x)\n",
+ __func__, bd.buffer1_size & 0xfff);
+ }
+ if ((bd.buffer2_size & 0xfff) != 0) {
+ DEBUGF_BRK("qemu:%s:ERROR...ERROR...ERROR... -- "
+ "xgmac buffer 2 len on send != 0 (0x%x)\n",
+ __func__, bd.buffer2_size & 0xfff);
+ }
+ if (len >= sizeof(frame)) {
+ DEBUGF_BRK("qemu:%s: buffer overflow %d read into %zu "
+ "buffer\n" , __func__, len, sizeof(frame));
+ DEBUGF_BRK("qemu:%s: buffer1.size=%d; buffer2.size=%d\n",
+ __func__, bd.buffer1_size, bd.buffer2_size);
+ }
+
+ cpu_physical_memory_read(bd.buffer1_addr, ptr, len);
+ ptr += len;
+ frame_size += len;
+ if (bd.ctl_stat & 0x20000000) {
+ /* Last buffer in frame. */
+ qemu_send_packet(&s->nic->nc, frame, len);
+ ptr = frame;
+ frame_size = 0;
+ s->regs[DMA_STATUS] |= DMA_STATUS_TI | DMA_STATUS_NIS;
+ }
+ bd.ctl_stat &= ~0x80000000;
+ /* Write back the modified descriptor. */
+ xgmac_write_desc(s, &bd, 0);
+ }
+}
+
+static void enet_update_irq(struct XgmacState *s)
+{
+ int stat = s->regs[DMA_STATUS] & s->regs[DMA_INTR_ENA];
+ qemu_set_irq(s->sbd_irq, !!stat);
+}
+
+static uint64_t enet_read(void *opaque, target_phys_addr_t addr, unsigned size)
+{
+ struct XgmacState *s = opaque;
+ uint64_t r = 0;
+ addr >>= 2;
+
+ switch (addr) {
+ case XGMAC_VERSION:
+ r = 0x1012;
+ break;
+ default:
+ if (addr < ARRAY_SIZE(s->regs)) {
+ r = s->regs[addr];
+ }
+ break;
+ }
+ return r;
+}
+
+static void enet_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ struct XgmacState *s = opaque;
+
+ addr >>= 2;
+ switch (addr) {
+ case DMA_BUS_MODE:
+ s->regs[DMA_BUS_MODE] = value & ~0x1;
+ break;
+ case DMA_XMT_POLL_DEMAND:
+ xgmac_enet_send(s);
+ break;
+ case DMA_STATUS:
+ s->regs[DMA_STATUS] = s->regs[DMA_STATUS] & ~value;
+ break;
+ case DMA_RCV_BASE_ADDR:
+ s->regs[DMA_RCV_BASE_ADDR] = s->regs[DMA_CUR_RX_DESC_ADDR] = value;
+ break;
+ case DMA_TX_BASE_ADDR:
+ s->regs[DMA_TX_BASE_ADDR] = s->regs[DMA_CUR_TX_DESC_ADDR] = value;
+ break;
+ default:
+ if (addr < ARRAY_SIZE(s->regs)) {
+ s->regs[addr] = value;
+ }
+ break;
+ }
+ enet_update_irq(s);
+}
+
+static const MemoryRegionOps enet_mem_ops = {
+ .read = enet_read,
+ .write = enet_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static int eth_can_rx(VLANClientState *nc)
+{
+ struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+ /* RX enabled? */
+ return s->regs[DMA_CONTROL] & DMA_CONTROL_SR;
+}
+
+static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+ struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff};
+ int unicast, broadcast, multicast;
+ struct desc bd;
+ ssize_t ret;
+
+ unicast = ~buf[0] & 0x1;
+ broadcast = memcmp(buf, sa_bcast, 6) == 0;
+ multicast = !unicast && !broadcast;
+ if (size < 12) {
+ s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+ ret = -1;
+ goto out;
+ }
+
+ xgmac_read_desc(s, &bd, 1);
+ if ((bd.ctl_stat & 0x80000000) == 0) {
+ s->regs[DMA_STATUS] |= DMA_STATUS_RU | DMA_STATUS_AIS;
+ ret = size;
+ goto out;
+ }
+
+ cpu_physical_memory_write(bd.buffer1_addr, buf, size);
+
+ /* Add in the 4 bytes for crc (the real hw returns length incl crc) */
+ size += 4;
+ bd.ctl_stat = (size << 16) | 0x300;
+ xgmac_write_desc(s, &bd, 1);
+
+ s->stats.rx_bytes += size;
+ s->stats.rx++;
+ if (multicast) {
+ s->stats.rx_mcast++;
+ } else if (broadcast) {
+ s->stats.rx_bcast++;
+ }
+
+ s->regs[DMA_STATUS] |= DMA_STATUS_RI | DMA_STATUS_NIS;
+ ret = size;
+
+out:
+ enet_update_irq(s);
+ return ret;
+}
+
+static void eth_cleanup(VLANClientState *nc)
+{
+ struct XgmacState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ s->nic = NULL;
+}
+
+static NetClientInfo net_xgmac_enet_info = {
+ .type = NET_CLIENT_TYPE_NIC,
+ .size = sizeof(NICState),
+ .can_receive = eth_can_rx,
+ .receive = eth_rx,
+ .cleanup = eth_cleanup,
+};
+
+static int xgmac_enet_init(SysBusDevice *dev)
+{
+ struct XgmacState *s = FROM_SYSBUS(typeof(*s), dev);
+
+ memory_region_init_io(&s->iomem, &enet_mem_ops, s, "xgmac", 0x1000);
+ sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_irq(dev, &s->sbd_irq);
+ sysbus_init_irq(dev, &s->pmt_irq);
+ sysbus_init_irq(dev, &s->mci_irq);
+
+ qemu_macaddr_default_if_unset(&s->conf.macaddr);
+ s->nic = qemu_new_nic(&net_xgmac_enet_info, &s->conf,
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+ qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
+
+ s->regs[XGMAC_ADDR_HIGH(0)] = (s->conf.macaddr.a[5] << 8) |
+ s->conf.macaddr.a[4];
+ s->regs[XGMAC_ADDR_LOW(0)] = (s->conf.macaddr.a[3] << 24) |
+ (s->conf.macaddr.a[2] << 16) |
+ (s->conf.macaddr.a[1] << 8) |
+ s->conf.macaddr.a[0];
+
+ return 0;
+}
+
+static Property xgmac_properties[] = {
+ DEFINE_NIC_PROPERTIES(struct XgmacState, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xgmac_enet_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ sbc->init = xgmac_enet_init;
+ dc->vmsd = &vmstate_xgmac;
+ dc->props = xgmac_properties;
+}
+
+static TypeInfo xgmac_enet_info = {
+ .name = "xgmac",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct XgmacState),
+ .class_init = xgmac_enet_class_init,
+};
+
+static void xgmac_enet_register(void)
+{
+ type_register_static(&xgmac_enet_info);
+}
+
+device_init(xgmac_enet_register)
diff --git a/hw/xilinx_axidma.c b/hw/xilinx_axidma.c
index 0da20d9565..e8a53123f9 100644
--- a/hw/xilinx_axidma.c
+++ b/hw/xilinx_axidma.c
@@ -486,20 +486,31 @@ static int xilinx_axidma_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo axidma_info = {
- .init = xilinx_axidma_init,
- .qdev.name = "xilinx,axidma",
- .qdev.size = sizeof(struct XilinxAXIDMA),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property axidma_properties[] = {
+ DEFINE_PROP_UINT32("freqhz", struct XilinxAXIDMA, freqhz, 50000000),
+ DEFINE_PROP_PTR("dmach", struct XilinxAXIDMA, dmach),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void axidma_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_axidma_init;
+ dc->props = axidma_properties;
+}
+
+static TypeInfo axidma_info = {
+ .name = "xilinx,axidma",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct XilinxAXIDMA),
+ .class_init = axidma_class_init,
};
static void xilinx_axidma_register(void)
{
- sysbus_register_withprop(&axidma_info);
+ type_register_static(&axidma_info);
}
device_init(xilinx_axidma_register)
diff --git a/hw/xilinx_axienet.c b/hw/xilinx_axienet.c
index a2eb3e6d5b..1ce2db4510 100644
--- a/hw/xilinx_axienet.c
+++ b/hw/xilinx_axienet.c
@@ -856,7 +856,7 @@ static int xilinx_enet_init(SysBusDevice *dev)
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
tdk_init(&s->TEMAC.phy);
@@ -870,22 +870,33 @@ static int xilinx_enet_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo xilinx_enet_info = {
- .init = xilinx_enet_init,
- .qdev.name = "xilinx,axienet",
- .qdev.size = sizeof(struct XilinxAXIEnet),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
- DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
- DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
- DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
- DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_enet_properties[] = {
+ DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
+ DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
+ DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
+ DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
+ DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_enet_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_enet_init;
+ dc->props = xilinx_enet_properties;
+}
+
+static TypeInfo xilinx_enet_info = {
+ .name = "xilinx,axienet",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct XilinxAXIEnet),
+ .class_init = xilinx_enet_class_init,
};
static void xilinx_enet_register(void)
{
- sysbus_register_withprop(&xilinx_enet_info);
+ type_register_static(&xilinx_enet_info);
}
device_init(xilinx_enet_register)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
index 6777254f35..499feef488 100644
--- a/hw/xilinx_ethlite.c
+++ b/hw/xilinx_ethlite.c
@@ -221,26 +221,37 @@ static int xilinx_ethlite_init(SysBusDevice *dev)
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
return 0;
}
-static SysBusDeviceInfo xilinx_ethlite_info = {
- .init = xilinx_ethlite_init,
- .qdev.name = "xilinx,ethlite",
- .qdev.size = sizeof(struct xlx_ethlite),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
- DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
- DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_ethlite_properties[] = {
+ DEFINE_PROP_UINT32("txpingpong", struct xlx_ethlite, c_tx_pingpong, 1),
+ DEFINE_PROP_UINT32("rxpingpong", struct xlx_ethlite, c_rx_pingpong, 1),
+ DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_ethlite_init;
+ dc->props = xilinx_ethlite_properties;
+}
+
+static TypeInfo xilinx_ethlite_info = {
+ .name = "xilinx,ethlite",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct xlx_ethlite),
+ .class_init = xilinx_ethlite_class_init,
};
static void xilinx_ethlite_register(void)
{
- sysbus_register_withprop(&xilinx_ethlite_info);
+ type_register_static(&xilinx_ethlite_info);
}
device_init(xilinx_ethlite_register)
diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c
index c567885bcf..73eed6dc5f 100644
--- a/hw/xilinx_intc.c
+++ b/hw/xilinx_intc.c
@@ -161,19 +161,30 @@ static int xilinx_intc_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo xilinx_intc_info = {
- .init = xilinx_intc_init,
- .qdev.name = "xilinx,intc",
- .qdev.size = sizeof(struct xlx_pic),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_intc_properties[] = {
+ DEFINE_PROP_UINT32("kind-of-intr", struct xlx_pic, c_kind_of_intr, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_intc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_intc_init;
+ dc->props = xilinx_intc_properties;
+}
+
+static TypeInfo xilinx_intc_info = {
+ .name = "xilinx,intc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct xlx_pic),
+ .class_init = xilinx_intc_class_init,
};
static void xilinx_intc_register(void)
{
- sysbus_register_withprop(&xilinx_intc_info);
+ type_register_static(&xilinx_intc_info);
}
device_init(xilinx_intc_register)
diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c
index adca53b98c..c8236d2e2a 100644
--- a/hw/xilinx_timer.c
+++ b/hw/xilinx_timer.c
@@ -219,20 +219,31 @@ static int xilinx_timer_init(SysBusDevice *dev)
return 0;
}
-static SysBusDeviceInfo xilinx_timer_info = {
- .init = xilinx_timer_init,
- .qdev.name = "xilinx,timer",
- .qdev.size = sizeof(struct timerblock),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 0),
- DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xilinx_timer_properties[] = {
+ DEFINE_PROP_UINT32("frequency", struct timerblock, freq_hz, 0),
+ DEFINE_PROP_UINT32("nr-timers", struct timerblock, nr_timers, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xilinx_timer_init;
+ dc->props = xilinx_timer_properties;
+}
+
+static TypeInfo xilinx_timer_info = {
+ .name = "xilinx,timer",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(struct timerblock),
+ .class_init = xilinx_timer_class_init,
};
static void xilinx_timer_register(void)
{
- sysbus_register_withprop(&xilinx_timer_info);
+ type_register_static(&xilinx_timer_info);
}
device_init(xilinx_timer_register)
diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c
index 6533df934f..1c2b9087b4 100644
--- a/hw/xilinx_uartlite.c
+++ b/hw/xilinx_uartlite.c
@@ -205,16 +205,29 @@ static int xilinx_uartlite_init(SysBusDevice *dev)
memory_region_init_io(&s->mmio, &uart_ops, s, "xilinx-uartlite", R_MAX * 4);
sysbus_init_mmio(dev, &s->mmio);
- s->chr = qdev_init_chardev(&dev->qdev);
+ s->chr = qemu_char_get_next_serial();
if (s->chr)
qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s);
return 0;
}
+static void xilinx_uartlite_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
+
+ sdc->init = xilinx_uartlite_init;
+}
+
+static TypeInfo xilinx_uartlite_info = {
+ .name = "xilinx,uartlite",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof (struct xlx_uartlite),
+ .class_init = xilinx_uartlite_class_init,
+};
+
static void xilinx_uart_register(void)
{
- sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite),
- xilinx_uartlite_init);
+ type_register_static(&xilinx_uartlite_info);
}
device_init(xilinx_uart_register)
diff --git a/hw/xio3130_downstream.c b/hw/xio3130_downstream.c
index d3c387d6cb..07e4fc1018 100644
--- a/hw/xio3130_downstream.c
+++ b/hw/xio3130_downstream.c
@@ -47,7 +47,7 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address,
static void xio3130_downstream_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
msi_reset(d);
pcie_cap_deverr_reset(d);
pcie_cap_slot_reset(d);
@@ -167,36 +167,45 @@ static const VMStateDescription vmstate_xio3130_downstream = {
}
};
-static PCIDeviceInfo xio3130_downstream_info = {
- .qdev.name = "xio3130-downstream",
- .qdev.desc = "TI X3130 Downstream Port of PCI Express Switch",
- .qdev.size = sizeof(PCIESlot),
- .qdev.reset = xio3130_downstream_reset,
- .qdev.vmsd = &vmstate_xio3130_downstream,
-
- .is_express = 1,
- .is_bridge = 1,
- .config_write = xio3130_downstream_write_config,
- .init = xio3130_downstream_initfn,
- .exit = xio3130_downstream_exitfn,
- .vendor_id = PCI_VENDOR_ID_TI,
- .device_id = PCI_DEVICE_ID_TI_XIO3130D,
- .revision = XIO3130_REVISION,
-
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
- DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
- DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
- DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
- port.br.dev.exp.aer_log.log_max,
- PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xio3130_downstream_properties[] = {
+ DEFINE_PROP_UINT8("port", PCIESlot, port.port, 0),
+ DEFINE_PROP_UINT8("chassis", PCIESlot, chassis, 0),
+ DEFINE_PROP_UINT16("slot", PCIESlot, slot, 0),
+ DEFINE_PROP_UINT16("aer_log_max", PCIESlot,
+ port.br.dev.exp.aer_log.log_max,
+ PCIE_AER_LOG_MAX_DEFAULT),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xio3130_downstream_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->config_write = xio3130_downstream_write_config;
+ k->init = xio3130_downstream_initfn;
+ k->exit = xio3130_downstream_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TI;
+ k->device_id = PCI_DEVICE_ID_TI_XIO3130D;
+ k->revision = XIO3130_REVISION;
+ dc->desc = "TI X3130 Downstream Port of PCI Express Switch";
+ dc->reset = xio3130_downstream_reset;
+ dc->vmsd = &vmstate_xio3130_downstream;
+ dc->props = xio3130_downstream_properties;
+}
+
+static TypeInfo xio3130_downstream_info = {
+ .name = "xio3130-downstream",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIESlot),
+ .class_init = xio3130_downstream_class_init,
};
static void xio3130_downstream_register(void)
{
- pci_qdev_register(&xio3130_downstream_info);
+ type_register_static(&xio3130_downstream_info);
}
device_init(xio3130_downstream_register);
diff --git a/hw/xio3130_upstream.c b/hw/xio3130_upstream.c
index 82836958a4..7887c92fcc 100644
--- a/hw/xio3130_upstream.c
+++ b/hw/xio3130_upstream.c
@@ -46,7 +46,7 @@ static void xio3130_upstream_write_config(PCIDevice *d, uint32_t address,
static void xio3130_upstream_reset(DeviceState *qdev)
{
- PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
+ PCIDevice *d = PCI_DEVICE(qdev);
msi_reset(d);
pci_bridge_reset(qdev);
pcie_cap_deverr_reset(d);
@@ -144,33 +144,42 @@ static const VMStateDescription vmstate_xio3130_upstream = {
}
};
-static PCIDeviceInfo xio3130_upstream_info = {
- .qdev.name = "x3130-upstream",
- .qdev.desc = "TI X3130 Upstream Port of PCI Express Switch",
- .qdev.size = sizeof(PCIEPort),
- .qdev.reset = xio3130_upstream_reset,
- .qdev.vmsd = &vmstate_xio3130_upstream,
-
- .is_express = 1,
- .is_bridge = 1,
- .config_write = xio3130_upstream_write_config,
- .init = xio3130_upstream_initfn,
- .exit = xio3130_upstream_exitfn,
- .vendor_id = PCI_VENDOR_ID_TI,
- .device_id = PCI_DEVICE_ID_TI_XIO3130U,
- .revision = XIO3130_REVISION,
-
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
- DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
- PCIE_AER_LOG_MAX_DEFAULT),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property xio3130_upstream_properties[] = {
+ DEFINE_PROP_UINT8("port", PCIEPort, port, 0),
+ DEFINE_PROP_UINT16("aer_log_max", PCIEPort, br.dev.exp.aer_log.log_max,
+ PCIE_AER_LOG_MAX_DEFAULT),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xio3130_upstream_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->is_express = 1;
+ k->is_bridge = 1;
+ k->config_write = xio3130_upstream_write_config;
+ k->init = xio3130_upstream_initfn;
+ k->exit = xio3130_upstream_exitfn;
+ k->vendor_id = PCI_VENDOR_ID_TI;
+ k->device_id = PCI_DEVICE_ID_TI_XIO3130U;
+ k->revision = XIO3130_REVISION;
+ dc->desc = "TI X3130 Upstream Port of PCI Express Switch";
+ dc->reset = xio3130_upstream_reset;
+ dc->vmsd = &vmstate_xio3130_upstream;
+ dc->props = xio3130_upstream_properties;
+}
+
+static TypeInfo xio3130_upstream_info = {
+ .name = "x3130-upstream",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(PCIEPort),
+ .class_init = xio3130_upstream_class_init,
};
static void xio3130_upstream_register(void)
{
- pci_qdev_register(&xio3130_upstream_info);
+ type_register_static(&xio3130_upstream_info);
}
device_init(xio3130_upstream_register);
diff --git a/hw/z2.c b/hw/z2.c
index 8d48488331..654ac55f5c 100644
--- a/hw/z2.c
+++ b/hw/z2.c
@@ -174,21 +174,30 @@ static VMStateDescription vmstate_zipit_lcd_state = {
}
};
-static SSISlaveInfo zipit_lcd_info = {
- .qdev.name = "zipit-lcd",
- .qdev.size = sizeof(ZipitLCD),
- .qdev.vmsd = &vmstate_zipit_lcd_state,
- .init = zipit_lcd_init,
- .transfer = zipit_lcd_transfer
+static void zipit_lcd_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
+
+ k->init = zipit_lcd_init;
+ k->transfer = zipit_lcd_transfer;
+ dc->vmsd = &vmstate_zipit_lcd_state;
+}
+
+static TypeInfo zipit_lcd_info = {
+ .name = "zipit-lcd",
+ .parent = TYPE_SSI_SLAVE,
+ .instance_size = sizeof(ZipitLCD),
+ .class_init = zipit_lcd_class_init,
};
typedef struct {
- i2c_slave i2c;
+ I2CSlave i2c;
int len;
uint8_t buf[3];
} AER915State;
-static int aer915_send(i2c_slave *i2c, uint8_t data)
+static int aer915_send(I2CSlave *i2c, uint8_t data)
{
AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
s->buf[s->len] = data;
@@ -206,7 +215,7 @@ static int aer915_send(i2c_slave *i2c, uint8_t data)
return 0;
}
-static void aer915_event(i2c_slave *i2c, enum i2c_event event)
+static void aer915_event(I2CSlave *i2c, enum i2c_event event)
{
AER915State *s = FROM_I2C_SLAVE(AER915State, i2c);
switch (event) {
@@ -225,7 +234,7 @@ static void aer915_event(i2c_slave *i2c, enum i2c_event event)
}
}
-static int aer915_recv(i2c_slave *slave)
+static int aer915_recv(I2CSlave *slave)
{
int retval = 0x00;
AER915State *s = FROM_I2C_SLAVE(AER915State, slave);
@@ -248,7 +257,7 @@ static int aer915_recv(i2c_slave *slave)
return retval;
}
-static int aer915_init(i2c_slave *i2c)
+static int aer915_init(I2CSlave *i2c)
{
/* Nothing to do. */
return 0;
@@ -266,14 +275,23 @@ static VMStateDescription vmstate_aer915_state = {
}
};
-static I2CSlaveInfo aer915_info = {
- .qdev.name = "aer915",
- .qdev.size = sizeof(AER915State),
- .qdev.vmsd = &vmstate_aer915_state,
- .init = aer915_init,
- .event = aer915_event,
- .recv = aer915_recv,
- .send = aer915_send
+static void aer915_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+
+ k->init = aer915_init;
+ k->event = aer915_event;
+ k->recv = aer915_recv;
+ k->send = aer915_send;
+ dc->vmsd = &vmstate_aer915_state;
+}
+
+static TypeInfo aer915_info = {
+ .name = "aer915",
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(AER915State),
+ .class_init = aer915_class_init,
};
static void z2_init(ram_addr_t ram_size,
@@ -326,8 +344,8 @@ static void z2_init(ram_addr_t ram_size,
NULL,
qdev_get_gpio_in(cpu->gpio, Z2_GPIO_SD_DETECT));
- ssi_register_slave(&zipit_lcd_info);
- i2c_register_slave(&aer915_info);
+ type_register_static(&zipit_lcd_info);
+ type_register_static(&aer915_info);
z2_lcd = ssi_create_slave(cpu->ssp[1], "zipit-lcd");
bus = pxa2xx_i2c_bus(cpu->i2c[0]);
i2c_create_slave(bus, "aer915", 0x55);
diff --git a/hw/zaurus.c b/hw/zaurus.c
index c4bcd29825..055df9b4e2 100644
--- a/hw/zaurus.c
+++ b/hw/zaurus.c
@@ -221,20 +221,31 @@ static const VMStateDescription vmstate_scoop_regs = {
},
};
-static SysBusDeviceInfo scoop_sysbus_info = {
- .init = scoop_init,
- .qdev.name = "scoop",
- .qdev.desc = "Scoop2 Sharp custom ASIC",
- .qdev.size = sizeof(ScoopInfo),
- .qdev.vmsd = &vmstate_scoop_regs,
- .qdev.props = (Property[]) {
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property scoop_sysbus_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = scoop_init;
+ dc->desc = "Scoop2 Sharp custom ASIC";
+ dc->vmsd = &vmstate_scoop_regs;
+ dc->props = scoop_sysbus_properties;
+}
+
+static TypeInfo scoop_sysbus_info = {
+ .name = "scoop",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ScoopInfo),
+ .class_init = scoop_sysbus_class_init,
};
static void scoop_register(void)
{
- sysbus_register_withprop(&scoop_sysbus_info);
+ type_register_static(&scoop_sysbus_info);
}
device_init(scoop_register);
diff --git a/include/qemu/object.h b/include/qemu/object.h
new file mode 100644
index 0000000000..9d0251d56a
--- /dev/null
+++ b/include/qemu/object.h
@@ -0,0 +1,662 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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.
+ *
+ */
+
+#ifndef QEMU_OBJECT_H
+#define QEMU_OBJECT_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "qemu-queue.h"
+
+struct Visitor;
+struct Error;
+
+struct TypeImpl;
+typedef struct TypeImpl *Type;
+
+typedef struct ObjectClass ObjectClass;
+typedef struct Object Object;
+
+typedef struct TypeInfo TypeInfo;
+
+typedef struct InterfaceClass InterfaceClass;
+typedef struct InterfaceInfo InterfaceInfo;
+
+#define TYPE_OBJECT NULL
+
+/**
+ * SECTION:object.h
+ * @title:Base Object Type System
+ * @short_description: interfaces for creating new types and objects
+ *
+ * The QEMU Object Model provides a framework for registering user creatable
+ * types and instantiating objects from those types. QOM provides the following
+ * features:
+ *
+ * - System for dynamically registering types
+ * - Support for single-inheritance of types
+ * - Multiple inheritance of stateless interfaces
+ *
+ * <example>
+ * <title>Creating a minimal type</title>
+ * <programlisting>
+ * #include "qdev.h"
+ *
+ * #define TYPE_MY_DEVICE "my-device"
+ *
+ * typedef struct MyDevice
+ * {
+ * DeviceState parent;
+ *
+ * int reg0, reg1, reg2;
+ * } MyDevice;
+ *
+ * static TypeInfo my_device_info = {
+ * .name = TYPE_MY_DEVICE,
+ * .parent = TYPE_DEVICE,
+ * .instance_size = sizeof(MyDevice),
+ * };
+ *
+ * static void my_device_module_init(void)
+ * {
+ * type_register_static(&my_device_info);
+ * }
+ *
+ * device_init(my_device_module_init);
+ * </programlisting>
+ * </example>
+ *
+ * In the above example, we create a simple type that is described by #TypeInfo.
+ * #TypeInfo describes information about the type including what it inherits
+ * from, the instance and class size, and constructor/destructor hooks.
+ *
+ * Every type has an #ObjectClass associated with it. #ObjectClass derivatives
+ * are instantiated dynamically but there is only ever one instance for any
+ * given type. The #ObjectClass typically holds a table of function pointers
+ * for the virtual methods implemented by this type.
+ *
+ * Using object_new(), a new #Object derivative will be instantiated. You can
+ * cast an #Object to a subclass (or base-class) type using
+ * object_dynamic_cast(). You typically want to define a macro wrapper around
+ * object_dynamic_cast_assert() to make it easier to convert to a specific type.
+ *
+ * # Class Initialization #
+ *
+ * Before an object is initialized, the class for the object must be
+ * initialized. There is only one class object for all instance objects
+ * that is created lazily.
+ *
+ * Classes are initialized by first initializing any parent classes (if
+ * necessary). After the parent class object has initialized, it will be
+ * copied into the current class object and any additional storage in the
+ * class object is zero filled.
+ *
+ * The effect of this is that classes automatically inherit any virtual
+ * function pointers that the parent class has already initialized. All
+ * other fields will be zero filled.
+ *
+ * Once all of the parent classes have been initialized, #TypeInfo::class_init
+ * is called to let the class being instantiated provide default initialize for
+ * it's virtual functions.
+ *
+ * # Interfaces #
+ *
+ * Interfaces allow a limited form of multiple inheritance. Instances are
+ * similar to normal types except for the fact that are only defined by
+ * their classes and never carry any state. You can dynamically cast an object
+ * to one of its #Interface types and vice versa.
+ */
+
+
+/**
+ * ObjectPropertyAccessor:
+ * @obj: the object that owns the property
+ * @v: the visitor that contains the property data
+ * @opaque: the object property opaque
+ * @name: the name of the property
+ * @errp: a pointer to an Error that is filled if getting/setting fails.
+ *
+ * Called when trying to get/set a property.
+ */
+typedef void (ObjectPropertyAccessor)(Object *obj,
+ struct Visitor *v,
+ void *opaque,
+ const char *name,
+ struct Error **errp);
+
+/**
+ * ObjectPropertyRelease:
+ * @obj: the object that owns the property
+ * @name: the name of the property
+ * @opaque: the opaque registered with the property
+ *
+ * Called when a property is removed from a object.
+ */
+typedef void (ObjectPropertyRelease)(Object *obj,
+ const char *name,
+ void *opaque);
+
+typedef struct ObjectProperty
+{
+ gchar *name;
+ gchar *type;
+ ObjectPropertyAccessor *get;
+ ObjectPropertyAccessor *set;
+ ObjectPropertyRelease *release;
+ void *opaque;
+
+ QTAILQ_ENTRY(ObjectProperty) node;
+} ObjectProperty;
+
+/**
+ * ObjectClass:
+ *
+ * The base for all classes. The only thing that #ObjectClass contains is an
+ * integer type handle.
+ */
+struct ObjectClass
+{
+ /*< private >*/
+ Type type;
+};
+
+/**
+ * Object:
+ *
+ * The base for all objects. The first member of this object is a pointer to
+ * a #ObjectClass. Since C guarantees that the first member of a structure
+ * always begins at byte 0 of that structure, as long as any sub-object places
+ * its parent as the first member, we can cast directly to a #Object.
+ *
+ * As a result, #Object contains a reference to the objects type as its
+ * first member. This allows identification of the real type of the object at
+ * run time.
+ *
+ * #Object also contains a list of #Interfaces that this object
+ * implements.
+ */
+struct Object
+{
+ /*< private >*/
+ ObjectClass *class;
+ GSList *interfaces;
+ QTAILQ_HEAD(, ObjectProperty) properties;
+ uint32_t ref;
+ Object *parent;
+};
+
+/**
+ * TypeInfo:
+ * @name: The name of the type.
+ * @parent: The name of the parent type.
+ * @instance_size: The size of the object (derivative of #Object). If
+ * @instance_size is 0, then the size of the object will be the size of the
+ * parent object.
+ * @instance_init: This function is called to initialize an object. The parent
+ * class will have already been initialized so the type is only responsible
+ * for initializing its own members.
+ * @instance_finalize: This function is called during object destruction. This
+ * is called before the parent @instance_finalize function has been called.
+ * An object should only free the members that are unique to its type in this
+ * function.
+ * @abstract: If this field is true, then the class is considered abstract and
+ * cannot be directly instantiated.
+ * @class_size: The size of the class object (derivative of #ObjectClass)
+ * for this object. If @class_size is 0, then the size of the class will be
+ * assumed to be the size of the parent class. This allows a type to avoid
+ * implementing an explicit class type if they are not adding additional
+ * virtual functions.
+ * @class_init: This function is called after all parent class initialization
+ * has occured to allow a class to set its default virtual method pointers.
+ * This is also the function to use to override virtual methods from a parent
+ * class.
+ * @class_finalize: This function is called during class destruction and is
+ * meant to release and dynamic parameters allocated by @class_init.
+ * @class_data: Data to pass to the @class_init and @class_finalize functions.
+ * This can be useful when building dynamic classes.
+ * @interfaces: The list of interfaces associated with this type. This
+ * should point to a static array that's terminated with a zero filled
+ * element.
+ */
+struct TypeInfo
+{
+ const char *name;
+ const char *parent;
+
+ size_t instance_size;
+ void (*instance_init)(Object *obj);
+ void (*instance_finalize)(Object *obj);
+
+ bool abstract;
+ size_t class_size;
+
+ void (*class_init)(ObjectClass *klass, void *data);
+ void (*class_finalize)(ObjectClass *klass, void *data);
+ void *class_data;
+
+ InterfaceInfo *interfaces;
+};
+
+/**
+ * OBJECT:
+ * @obj: A derivative of #Object
+ *
+ * Converts an object to a #Object. Since all objects are #Objects,
+ * this function will always succeed.
+ */
+#define OBJECT(obj) \
+ ((Object *)(obj))
+
+/**
+ * OBJECT_CHECK:
+ * @type: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: The QOM typename of @type
+ *
+ * A type safe version of @object_dynamic_cast_assert. Typically each class
+ * will define a macro based on this type to perform type safe dynamic_casts to
+ * this object type.
+ *
+ * If an invalid object is passed to this function, a run time assert will be
+ * generated.
+ */
+#define OBJECT_CHECK(type, obj, name) \
+ ((type *)object_dynamic_cast_assert((Object *)(obj), (name)))
+
+/**
+ * OBJECT_CLASS_CHECK:
+ * @class: The C type to use for the return value.
+ * @obj: A derivative of @type to cast.
+ * @name: the QOM typename of @class.
+ *
+ * A type safe version of @object_check_class. This macro is typically wrapped
+ * by each type to perform type safe casts of a class to a specific class type.
+ */
+#define OBJECT_CLASS_CHECK(class, obj, name) \
+ ((class *)object_class_dynamic_cast_assert((ObjectClass *)(obj), (name)))
+
+/**
+ * OBJECT_GET_CLASS:
+ * @class: The C type to use for the return value.
+ * @obj: The object to obtain the class for.
+ * @name: The QOM typename of @obj.
+ *
+ * This function will return a specific class for a given object. Its generally
+ * used by each type to provide a type safe macro to get a specific class type
+ * from an object.
+ */
+#define OBJECT_GET_CLASS(class, obj, name) \
+ OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
+
+#define OBJECT_CLASS(class) \
+ ((ObjectClass *)(class))
+
+/**
+ * InterfaceClass:
+ * @parent_class: the base class
+ *
+ * The class for all interfaces. Subclasses of this class should only add
+ * virtual methods.
+ */
+struct InterfaceClass
+{
+ ObjectClass parent_class;
+};
+
+/**
+ * InterfaceInfo:
+ * @type: The name of the interface.
+ * @interface_initfn: This method is called during class initialization and is
+ * used to initialize an interface associated with a class. This function
+ * should initialize any default virtual functions for a class and/or override
+ * virtual functions in a parent class.
+ *
+ * The information associated with an interface.
+ */
+struct InterfaceInfo
+{
+ const char *type;
+
+ void (*interface_initfn)(ObjectClass *class, void *data);
+};
+
+#define TYPE_INTERFACE "interface"
+
+/**
+ * object_new:
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory. This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new(const char *typename);
+
+/**
+ * object_new_with_type:
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize a new object using heap allocated memory. This
+ * function should be paired with object_delete() to free the resources
+ * associated with the object.
+ *
+ * Returns: The newly allocated and instantiated object.
+ */
+Object *object_new_with_type(Type type);
+
+/**
+ * object_delete:
+ * @obj: The object to free.
+ *
+ * Finalize an object and then free the memory associated with it. This should
+ * be paired with object_new() to free the resources associated with an object.
+ */
+void object_delete(Object *obj);
+
+/**
+ * object_initialize_with_type:
+ * @obj: A pointer to the memory to be used for the object.
+ * @type: The type of the object to instantiate.
+ *
+ * This function will initialize an object. The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize_with_type(void *data, Type type);
+
+/**
+ * object_initialize:
+ * @obj: A pointer to the memory to be used for the object.
+ * @typename: The name of the type of the object to instantiate.
+ *
+ * This function will initialize an object. The memory for the object should
+ * have already been allocated.
+ */
+void object_initialize(void *obj, const char *typename);
+
+/**
+ * object_finalize:
+ * @obj: The object to finalize.
+ *
+ * This function destroys and object without freeing the memory associated with
+ * it.
+ */
+void object_finalize(void *obj);
+
+/**
+ * object_dynamic_cast:
+ * @obj: The object to cast.
+ * @typename: The @typename to cast to.
+ *
+ * This function will determine if @obj is-a @typename. @obj can refer to an
+ * object or an interface associated with an object.
+ *
+ * Returns: This function returns @obj on success or #NULL on failure.
+ */
+Object *object_dynamic_cast(Object *obj, const char *typename);
+
+/**
+ * @object_dynamic_cast_assert:
+ *
+ * See object_dynamic_cast() for a description of the parameters of this
+ * function. The only difference in behavior is that this function asserts
+ * instead of returning #NULL on failure.
+ */
+Object *object_dynamic_cast_assert(Object *obj, const char *typename);
+
+/**
+ * object_get_class:
+ * @obj: A derivative of #Object
+ *
+ * Returns: The #ObjectClass of the type associated with @obj.
+ */
+ObjectClass *object_get_class(Object *obj);
+
+/**
+ * object_get_typename:
+ * @obj: A derivative of #Object.
+ *
+ * Returns: The QOM typename of @obj.
+ */
+const char *object_get_typename(Object *obj);
+
+/**
+ * type_register_static:
+ * @info: The #TypeInfo of the new type.
+ *
+ * @info and all of the strings it points to should exist for the life time
+ * that the type is registered.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register_static(const TypeInfo *info);
+
+#define type_register_static_alias(info, name) do { } while (0)
+
+/**
+ * type_register:
+ * @info: The #TypeInfo of the new type
+ *
+ * Unlike type_register_static(), this call does not require @info or it's
+ * string members to continue to exist after the call returns.
+ *
+ * Returns: 0 on failure, the new #Type on success.
+ */
+Type type_register(const TypeInfo *info);
+
+/**
+ * object_class_dynamic_cast_assert:
+ * @klass: The #ObjectClass to attempt to cast.
+ * @typename: The QOM typename of the class to cast to.
+ *
+ * Returns: This function always returns @klass and asserts on failure.
+ */
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *klass,
+ const char *typename);
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
+ const char *typename);
+
+/**
+ * object_class_get_name:
+ * @klass: The class to obtain the QOM typename for.
+ *
+ * Returns: The QOM typename for @klass.
+ */
+const char *object_class_get_name(ObjectClass *klass);
+
+ObjectClass *object_class_by_name(const char *typename);
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+ const char *implements_type, bool include_abstract,
+ void *opaque);
+/**
+ * object_ref:
+ * @obj: the object
+ *
+ * Increase the reference count of a object. A object cannot be freed as long
+ * as its reference count is greater than zero.
+ */
+void object_ref(Object *obj);
+
+/**
+ * qdef_unref:
+ * @obj: the object
+ *
+ * Decrease the reference count of a object. A object cannot be freed as long
+ * as its reference count is greater than zero.
+ */
+void object_unref(Object *obj);
+
+/**
+ * object_property_add:
+ * @obj: the object to add a property to
+ * @name: the name of the property. This can contain any character except for
+ * a forward slash. In general, you should use hyphens '-' instead of
+ * underscores '_' when naming properties.
+ * @type: the type name of the property. This namespace is pretty loosely
+ * defined. Sub namespaces are constructed by using a prefix and then
+ * to angle brackets. For instance, the type 'virtio-net-pci' in the
+ * 'link' namespace would be 'link<virtio-net-pci>'.
+ * @get: The getter to be called to read a property. If this is NULL, then
+ * the property cannot be read.
+ * @set: the setter to be called to write a property. If this is NULL,
+ * then the property cannot be written.
+ * @release: called when the property is removed from the object. This is
+ * meant to allow a property to free its opaque upon object
+ * destruction. This may be NULL.
+ * @opaque: an opaque pointer to pass to the callbacks for the property
+ * @errp: returns an error if this function fails
+ */
+void object_property_add(Object *obj, const char *name, const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, struct Error **errp);
+
+void object_property_del(Object *obj, const char *name, struct Error **errp);
+
+void object_unparent(Object *obj);
+
+/**
+ * object_property_get:
+ * @obj: the object
+ * @v: the visitor that will receive the property value. This should be an
+ * Output visitor and the data will be written with @name as the name.
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Reads a property from a object.
+ */
+void object_property_get(Object *obj, struct Visitor *v, const char *name,
+ struct Error **errp);
+
+/**
+ * object_property_set:
+ * @obj: the object
+ * @v: the visitor that will be used to write the property value. This should
+ * be an Input visitor and the data will be first read with @name as the
+ * name and then written as the property value.
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Writes a property to a object.
+ */
+void object_property_set(Object *obj, struct Visitor *v, const char *name,
+ struct Error **errp);
+
+/**
+ * @object_property_get_type:
+ * @obj: the object
+ * @name: the name of the property
+ * @errp: returns an error if this function fails
+ *
+ * Returns: The type name of the property.
+ */
+const char *object_property_get_type(Object *obj, const char *name,
+ struct Error **errp);
+
+/**
+ * object_get_root:
+ *
+ * Returns: the root object of the composition tree
+ */
+Object *object_get_root(void);
+
+/**
+ * object_get_canonical_path:
+ *
+ * Returns: The canonical path for a object. This is the path within the
+ * composition tree starting from the root.
+ */
+gchar *object_get_canonical_path(Object *obj);
+
+/**
+ * object_resolve_path:
+ * @path: the path to resolve
+ * @ambiguous: returns true if the path resolution failed because of an
+ * ambiguous match
+ *
+ * There are two types of supported paths--absolute paths and partial paths.
+ *
+ * Absolute paths are derived from the root object and can follow child<> or
+ * link<> properties. Since they can follow link<> properties, they can be
+ * arbitrarily long. Absolute paths look like absolute filenames and are
+ * prefixed with a leading slash.
+ *
+ * Partial paths look like relative filenames. They do not begin with a
+ * prefix. The matching rules for partial paths are subtle but designed to make
+ * specifying objects easy. At each level of the composition tree, the partial
+ * path is matched as an absolute path. The first match is not returned. At
+ * least two matches are searched for. A successful result is only returned if
+ * only one match is founded. If more than one match is found, a flag is
+ * return to indicate that the match was ambiguous.
+ *
+ * Returns: The matched object or NULL on path lookup failure.
+ */
+Object *object_resolve_path(const char *path, bool *ambiguous);
+
+/**
+ * object_property_add_child:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @child: the child object
+ * @errp: if an error occurs, a pointer to an area to store the area
+ *
+ * Child properties form the composition tree. All objects need to be a child
+ * of another object. Objects can only be a child of one object.
+ *
+ * There is no way for a child to determine what its parent is. It is not
+ * a bidirectional relationship. This is by design.
+ */
+void object_property_add_child(Object *obj, const char *name,
+ Object *child, struct Error **errp);
+
+/**
+ * object_property_add_link:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @type: the qobj type of the link
+ * @child: a pointer to where the link object reference is stored
+ * @errp: if an error occurs, a pointer to an area to store the area
+ *
+ * Links establish relationships between objects. Links are unidirectional
+ * although two links can be combined to form a bidirectional relationship
+ * between objects.
+ *
+ * Links form the graph in the object model.
+ */
+void object_property_add_link(Object *obj, const char *name,
+ const char *type, Object **child,
+ struct Error **errp);
+
+/**
+ * object_property_add_str:
+ * @obj: the object to add a property to
+ * @name: the name of the property
+ * @get: the getter or NULL if the property is write-only. This function must
+ * return a string to be freed by g_free().
+ * @set: the setter or NULL if the property is read-only
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Add a string property using getters/setters. This function will add a
+ * property of type 'string'.
+ */
+void object_property_add_str(Object *obj, const char *name,
+ char *(*get)(Object *, struct Error **),
+ void (*set)(Object *, const char *, struct Error **),
+ struct Error **errp);
+
+#endif
diff --git a/kvm-all.c b/kvm-all.c
index 2cc4562921..0b87658f6a 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -78,6 +78,13 @@ struct KVMState
int pit_in_kernel;
int xsave, xcrs;
int many_ioeventfds;
+ int irqchip_inject_ioctl;
+#ifdef KVM_CAP_IRQ_ROUTING
+ struct kvm_irq_routing *irq_routes;
+ int nr_allocated_irq_routes;
+ uint32_t *used_gsi_bitmap;
+ unsigned int max_gsi;
+#endif
};
KVMState *kvm_state;
@@ -344,7 +351,8 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
unsigned long *bitmap)
{
unsigned int i, j;
- unsigned long page_number, addr, addr1, c;
+ unsigned long page_number, c;
+ target_phys_addr_t addr, addr1;
unsigned int len = ((section->size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
/*
@@ -360,7 +368,7 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
page_number = i * HOST_LONG_BITS + j;
addr1 = page_number * TARGET_PAGE_SIZE;
addr = section->offset_within_region + addr1;
- memory_region_set_dirty(section->mr, addr);
+ memory_region_set_dirty(section->mr, addr, TARGET_PAGE_SIZE);
} while (c != 0);
}
}
@@ -371,8 +379,9 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
/**
* kvm_physical_sync_dirty_bitmap - Grab dirty bitmap from kernel space
- * This function updates qemu's dirty bitmap using cpu_physical_memory_set_dirty().
- * This means all bits are set to dirty.
+ * This function updates qemu's dirty bitmap using
+ * memory_region_set_dirty(). This means all bits are set
+ * to dirty.
*
* @start_add: start of logged region.
* @end_addr: end of logged region.
@@ -728,6 +737,138 @@ static void kvm_handle_interrupt(CPUState *env, int mask)
}
}
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
+{
+ struct kvm_irq_level event;
+ int ret;
+
+ assert(s->irqchip_in_kernel);
+
+ event.level = level;
+ event.irq = irq;
+ ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event);
+ if (ret < 0) {
+ perror("kvm_set_irqchip_line");
+ abort();
+ }
+
+ return (s->irqchip_inject_ioctl == KVM_IRQ_LINE) ? 1 : event.status;
+}
+
+#ifdef KVM_CAP_IRQ_ROUTING
+static void set_gsi(KVMState *s, unsigned int gsi)
+{
+ assert(gsi < s->max_gsi);
+
+ s->used_gsi_bitmap[gsi / 32] |= 1U << (gsi % 32);
+}
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+ int gsi_count;
+
+ gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING);
+ if (gsi_count > 0) {
+ unsigned int gsi_bits, i;
+
+ /* Round up so we can search ints using ffs */
+ gsi_bits = (gsi_count + 31) / 32;
+ s->used_gsi_bitmap = g_malloc0(gsi_bits / 8);
+ s->max_gsi = gsi_bits;
+
+ /* Mark any over-allocated bits as already in use */
+ for (i = gsi_count; i < gsi_bits; i++) {
+ set_gsi(s, i);
+ }
+ }
+
+ s->irq_routes = g_malloc0(sizeof(*s->irq_routes));
+ s->nr_allocated_irq_routes = 0;
+
+ kvm_arch_init_irq_routing(s);
+}
+
+static void kvm_add_routing_entry(KVMState *s,
+ struct kvm_irq_routing_entry *entry)
+{
+ struct kvm_irq_routing_entry *new;
+ int n, size;
+
+ if (s->irq_routes->nr == s->nr_allocated_irq_routes) {
+ n = s->nr_allocated_irq_routes * 2;
+ if (n < 64) {
+ n = 64;
+ }
+ size = sizeof(struct kvm_irq_routing);
+ size += n * sizeof(*new);
+ s->irq_routes = g_realloc(s->irq_routes, size);
+ s->nr_allocated_irq_routes = n;
+ }
+ n = s->irq_routes->nr++;
+ new = &s->irq_routes->entries[n];
+ memset(new, 0, sizeof(*new));
+ new->gsi = entry->gsi;
+ new->type = entry->type;
+ new->flags = entry->flags;
+ new->u = entry->u;
+
+ set_gsi(s, entry->gsi);
+}
+
+void kvm_irqchip_add_route(KVMState *s, int irq, int irqchip, int pin)
+{
+ struct kvm_irq_routing_entry e;
+
+ e.gsi = irq;
+ e.type = KVM_IRQ_ROUTING_IRQCHIP;
+ e.flags = 0;
+ e.u.irqchip.irqchip = irqchip;
+ e.u.irqchip.pin = pin;
+ kvm_add_routing_entry(s, &e);
+}
+
+int kvm_irqchip_commit_routes(KVMState *s)
+{
+ s->irq_routes->flags = 0;
+ return kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, s->irq_routes);
+}
+
+#else /* !KVM_CAP_IRQ_ROUTING */
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+}
+#endif /* !KVM_CAP_IRQ_ROUTING */
+
+static int kvm_irqchip_create(KVMState *s)
+{
+ QemuOptsList *list = qemu_find_opts("machine");
+ int ret;
+
+ if (QTAILQ_EMPTY(&list->head) ||
+ !qemu_opt_get_bool(QTAILQ_FIRST(&list->head),
+ "kernel_irqchip", false) ||
+ !kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
+ return 0;
+ }
+
+ ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
+ if (ret < 0) {
+ fprintf(stderr, "Create kernel irqchip failed\n");
+ return ret;
+ }
+
+ s->irqchip_inject_ioctl = KVM_IRQ_LINE;
+ if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
+ s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+ }
+ s->irqchip_in_kernel = 1;
+
+ kvm_init_irq_routing(s);
+
+ return 0;
+}
+
int kvm_init(void)
{
static const char upgrade_note[] =
@@ -823,6 +964,11 @@ int kvm_init(void)
goto err;
}
+ ret = kvm_irqchip_create(s);
+ if (ret < 0) {
+ goto err;
+ }
+
kvm_state = s;
memory_listener_register(&kvm_memory_listener);
@@ -1158,6 +1304,20 @@ int kvm_has_many_ioeventfds(void)
return kvm_state->many_ioeventfds;
}
+int kvm_has_gsi_routing(void)
+{
+#ifdef KVM_CAP_IRQ_ROUTING
+ return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+#else
+ return false;
+#endif
+}
+
+int kvm_allows_irq0_override(void)
+{
+ return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+}
+
void kvm_setup_guest_memory(void *start, size_t size)
{
if (!kvm_has_sync_mmu()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index 06064b9a86..6c2b06ba32 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,6 +78,11 @@ int kvm_has_many_ioeventfds(void)
return 0;
}
+int kvm_allows_irq0_override(void)
+{
+ return 1;
+}
+
void kvm_setup_guest_memory(void *start, size_t size)
{
}
diff --git a/kvm.h b/kvm.h
index c1de81a11c..40b5ffcfa3 100644
--- a/kvm.h
+++ b/kvm.h
@@ -31,6 +31,7 @@ extern int kvm_allowed;
#endif
struct kvm_run;
+struct kvm_lapic_state;
typedef struct KVMCapabilityInfo {
const char *name;
@@ -51,6 +52,9 @@ int kvm_has_debugregs(void);
int kvm_has_xsave(void);
int kvm_has_xcrs(void);
int kvm_has_many_ioeventfds(void);
+int kvm_has_gsi_routing(void);
+
+int kvm_allows_irq0_override(void);
#ifdef NEED_CPU_H
int kvm_init_vcpu(CPUState *env);
@@ -124,6 +128,16 @@ void kvm_arch_reset_vcpu(CPUState *env);
int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr);
int kvm_arch_on_sigbus(int code, void *addr);
+void kvm_arch_init_irq_routing(KVMState *s);
+
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
+
+void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
+int kvm_irqchip_commit_routes(KVMState *s);
+
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+
struct kvm_guest_debug;
struct kvm_debug_exit_arch;
diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h
index fb3fddcd87..b921c3f489 100644
--- a/linux-headers/asm-powerpc/kvm.h
+++ b/linux-headers/asm-powerpc/kvm.h
@@ -265,12 +265,9 @@ struct kvm_debug_exit_arch {
struct kvm_guest_debug_arch {
};
-#define KVM_REG_MASK 0x001f
-#define KVM_REG_EXT_MASK 0xffe0
-#define KVM_REG_GPR 0x0000
-#define KVM_REG_FPR 0x0020
-#define KVM_REG_QPR 0x0040
-#define KVM_REG_FQPR 0x0060
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
#define KVM_INTERRUPT_SET -1U
#define KVM_INTERRUPT_UNSET -2U
@@ -327,6 +324,6 @@ struct kvm_book3e_206_tlb_params {
__u32 reserved[8];
};
-#define KVM_ONE_REG_PPC_HIOR KVM_ONE_REG_PPC | 0x100
+#define KVM_REG_PPC_HIOR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/linux-headers/asm-powerpc/kvm_para.h b/linux-headers/asm-powerpc/kvm_para.h
index ad58c90bf5..c047a84000 100644
--- a/linux-headers/asm-powerpc/kvm_para.h
+++ b/linux-headers/asm-powerpc/kvm_para.h
@@ -22,6 +22,16 @@
#include <linux/types.h>
+/*
+ * Additions to this struct must only occur at the end, and should be
+ * accompanied by a KVM_MAGIC_FEAT flag to advertise that they are present
+ * (albeit not necessarily relevant to the current target hardware platform).
+ *
+ * Struct fields are always 32 or 64 bit aligned, depending on them being 32
+ * or 64 bit wide respectively.
+ *
+ * See Documentation/virtual/kvm/ppc-pv.txt
+ */
struct kvm_vcpu_arch_shared {
__u64 scratch1;
__u64 scratch2;
@@ -33,11 +43,35 @@ struct kvm_vcpu_arch_shared {
__u64 sprg3;
__u64 srr0;
__u64 srr1;
- __u64 dar;
+ __u64 dar; /* dear on BookE */
__u64 msr;
__u32 dsisr;
__u32 int_pending; /* Tells the guest if we have an interrupt */
__u32 sr[16];
+ __u32 mas0;
+ __u32 mas1;
+ __u64 mas7_3;
+ __u64 mas2;
+ __u32 mas4;
+ __u32 mas6;
+ __u32 esr;
+ __u32 pir;
+
+ /*
+ * SPRG4-7 are user-readable, so we can only keep these consistent
+ * between the shared area and the real registers when there's an
+ * intervening exit to KVM. This also applies to SPRG3 on some
+ * chips.
+ *
+ * This suffices for access by guest userspace, since in PR-mode
+ * KVM, an exit must occur when changing the guest's MSR[PR].
+ * If the guest kernel writes to SPRG3-7 via the shared area, it
+ * must also use the shared area for reading while in kernel space.
+ */
+ __u64 sprg4;
+ __u64 sprg5;
+ __u64 sprg6;
+ __u64 sprg7;
};
#define KVM_SC_MAGIC_R0 0x4b564d21 /* "KVM!" */
@@ -47,7 +81,10 @@ struct kvm_vcpu_arch_shared {
#define KVM_FEATURE_MAGIC_PAGE 1
-#define KVM_MAGIC_FEAT_SR (1 << 0)
+#define KVM_MAGIC_FEAT_SR (1 << 0)
+
+/* MASn, ESR, PIR, and high SPRGs */
+#define KVM_MAGIC_FEAT_MAS0_TO_SPRG7 (1 << 1)
#endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index 82b32a100c..9acbde4af2 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -41,4 +41,13 @@ struct kvm_debug_exit_arch {
struct kvm_guest_debug_arch {
};
+#define KVM_SYNC_PREFIX (1UL << 0)
+#define KVM_SYNC_GPRS (1UL << 1)
+#define KVM_SYNC_ACRS (1UL << 2)
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+ __u64 prefix; /* prefix register */
+ __u64 gprs[16]; /* general purpose registers */
+ __u32 acrs[16]; /* access registers */
+};
#endif
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index 5df477ac3a..b80420bcd0 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -189,5 +189,6 @@
#define HV_STATUS_INVALID_HYPERCALL_CODE 2
#define HV_STATUS_INVALID_HYPERCALL_INPUT 3
#define HV_STATUS_INVALID_ALIGNMENT 4
+#define HV_STATUS_INSUFFICIENT_BUFFERS 19
#endif
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index 4d8dcbdfc1..e7d1c194d2 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -321,4 +321,8 @@ struct kvm_xcrs {
__u64 padding[16];
};
+/* definition of registers in kvm_run */
+struct kvm_sync_regs {
+};
+
#endif /* _ASM_X86_KVM_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index a8761d3be6..f6b53432db 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -162,6 +162,7 @@ struct kvm_pit_config {
#define KVM_EXIT_INTERNAL_ERROR 17
#define KVM_EXIT_OSI 18
#define KVM_EXIT_PAPR_HCALL 19
+#define KVM_EXIT_S390_UCONTROL 20
/* For KVM_EXIT_INTERNAL_ERROR */
#define KVM_INTERNAL_ERROR_EMULATION 1
@@ -249,6 +250,11 @@ struct kvm_run {
#define KVM_S390_RESET_CPU_INIT 8
#define KVM_S390_RESET_IPL 16
__u64 s390_reset_flags;
+ /* KVM_EXIT_S390_UCONTROL */
+ struct {
+ __u64 trans_exc_code;
+ __u32 pgm_code;
+ } s390_ucontrol;
/* KVM_EXIT_DCR */
struct {
__u32 dcrn;
@@ -273,6 +279,20 @@ struct kvm_run {
/* Fix the size of the union. */
char padding[256];
};
+
+ /*
+ * shared registers between kvm and userspace.
+ * kvm_valid_regs specifies the register classes set by the host
+ * kvm_dirty_regs specified the register classes dirtied by userspace
+ * struct kvm_sync_regs is architecture specific, as well as the
+ * bits for kvm_valid_regs and kvm_dirty_regs
+ */
+ __u64 kvm_valid_regs;
+ __u64 kvm_dirty_regs;
+ union {
+ struct kvm_sync_regs regs;
+ char padding[1024];
+ } s;
};
/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
@@ -371,6 +391,7 @@ struct kvm_s390_psw {
#define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u
#define KVM_S390_INT_EMERGENCY 0xffff1201u
+#define KVM_S390_INT_EXTERNAL_CALL 0xffff1202u
struct kvm_s390_interrupt {
__u32 type;
@@ -430,6 +451,11 @@ struct kvm_ppc_pvinfo {
#define KVMIO 0xAE
+/* machine type bits, to be used as argument to KVM_CREATE_VM */
+#define KVM_VM_S390_UCONTROL 1
+
+#define KVM_S390_SIE_PAGE_OFFSET 1
+
/*
* ioctls for /dev/kvm fds:
*/
@@ -558,6 +584,10 @@ struct kvm_ppc_pvinfo {
#define KVM_CAP_PPC_PAPR 68
#define KVM_CAP_SW_TLB 69
#define KVM_CAP_ONE_REG 70
+#define KVM_CAP_S390_GMAP 71
+#define KVM_CAP_TSC_DEADLINE_TIMER 72
+#define KVM_CAP_S390_UCONTROL 73
+#define KVM_CAP_SYNC_REGS 74
#ifdef KVM_CAP_IRQ_ROUTING
@@ -654,30 +684,33 @@ struct kvm_dirty_tlb {
/* Available with KVM_CAP_ONE_REG */
-#define KVM_ONE_REG_GENERIC 0x0000000000000000ULL
+#define KVM_REG_ARCH_MASK 0xff00000000000000ULL
+#define KVM_REG_GENERIC 0x0000000000000000ULL
/*
* Architecture specific registers are to be defined in arch headers and
* ORed with the arch identifier.
*/
-#define KVM_ONE_REG_PPC 0x1000000000000000ULL
-#define KVM_ONE_REG_X86 0x2000000000000000ULL
-#define KVM_ONE_REG_IA64 0x3000000000000000ULL
-#define KVM_ONE_REG_ARM 0x4000000000000000ULL
-#define KVM_ONE_REG_S390 0x5000000000000000ULL
+#define KVM_REG_PPC 0x1000000000000000ULL
+#define KVM_REG_X86 0x2000000000000000ULL
+#define KVM_REG_IA64 0x3000000000000000ULL
+#define KVM_REG_ARM 0x4000000000000000ULL
+#define KVM_REG_S390 0x5000000000000000ULL
+
+#define KVM_REG_SIZE_SHIFT 52
+#define KVM_REG_SIZE_MASK 0x00f0000000000000ULL
+#define KVM_REG_SIZE_U8 0x0000000000000000ULL
+#define KVM_REG_SIZE_U16 0x0010000000000000ULL
+#define KVM_REG_SIZE_U32 0x0020000000000000ULL
+#define KVM_REG_SIZE_U64 0x0030000000000000ULL
+#define KVM_REG_SIZE_U128 0x0040000000000000ULL
+#define KVM_REG_SIZE_U256 0x0050000000000000ULL
+#define KVM_REG_SIZE_U512 0x0060000000000000ULL
+#define KVM_REG_SIZE_U1024 0x0070000000000000ULL
struct kvm_one_reg {
__u64 id;
- union {
- __u8 reg8;
- __u16 reg16;
- __u32 reg32;
- __u64 reg64;
- __u8 reg128[16];
- __u8 reg256[32];
- __u8 reg512[64];
- __u8 reg1024[128];
- } u;
+ __u64 addr;
};
/*
@@ -698,6 +731,17 @@ struct kvm_one_reg {
struct kvm_userspace_memory_region)
#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
+
+/* enable ucontrol for s390 */
+struct kvm_s390_ucas_mapping {
+ __u64 user_addr;
+ __u64 vcpu_addr;
+ __u64 length;
+};
+#define KVM_S390_UCAS_MAP _IOW(KVMIO, 0x50, struct kvm_s390_ucas_mapping)
+#define KVM_S390_UCAS_UNMAP _IOW(KVMIO, 0x51, struct kvm_s390_ucas_mapping)
+#define KVM_S390_VCPU_FAULT _IOW(KVMIO, 0x52, unsigned long)
+
/* Device model IOC */
#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60)
#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
@@ -809,7 +853,7 @@ struct kvm_one_reg {
/* Available with KVM_CAP_SW_TLB */
#define KVM_DIRTY_TLB _IOW(KVMIO, 0xaa, struct kvm_dirty_tlb)
/* Available with KVM_CAP_ONE_REG */
-#define KVM_GET_ONE_REG _IOWR(KVMIO, 0xab, struct kvm_one_reg)
+#define KVM_GET_ONE_REG _IOW(KVMIO, 0xab, struct kvm_one_reg)
#define KVM_SET_ONE_REG _IOW(KVMIO, 0xac, struct kvm_one_reg)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
diff --git a/linux-headers/linux/kvm_para.h b/linux-headers/linux/kvm_para.h
index b315e27a9c..7bdcf93c1d 100644
--- a/linux-headers/linux/kvm_para.h
+++ b/linux-headers/linux/kvm_para.h
@@ -26,4 +26,3 @@
#include <asm/kvm_para.h>
#endif /* __LINUX_KVM_PARA_H */
-
diff --git a/linux-headers/linux/virtio_ring.h b/linux-headers/linux/virtio_ring.h
index 78289eedf2..1b333e2536 100644
--- a/linux-headers/linux/virtio_ring.h
+++ b/linux-headers/linux/virtio_ring.h
@@ -135,13 +135,13 @@ static __inline__ void vring_init(struct vring *vr, unsigned int num, void *p,
vr->num = num;
vr->desc = p;
vr->avail = p + num*sizeof(struct vring_desc);
- vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + align-1)
- & ~(align - 1));
+ vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__u16)
+ + align-1) & ~(align - 1));
}
static __inline__ unsigned vring_size(unsigned int num, unsigned long align)
{
- return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
+ return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
+ align - 1) & ~(align - 1))
+ sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
}
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 845be8be3b..2fd4a93f8a 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1245,6 +1245,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
struct image_info *interp_info)
{
abi_ulong sp;
+ abi_ulong sp_auxv;
int size;
int i;
abi_ulong u_rand_bytes;
@@ -1316,6 +1317,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
sp -= n; put_user_ual(id, sp); \
} while(0)
+ sp_auxv = sp;
NEW_AUX_ENT (AT_NULL, 0);
/* There must be exactly DLINFO_ITEMS entries here. */
@@ -1346,6 +1348,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
#undef NEW_AUX_ENT
info->saved_auxv = sp;
+ info->auxv_len = sp_auxv - sp;
sp = loader_build_argptr(envc, argc, sp, p, 0);
return sp;
@@ -2326,9 +2329,8 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
{
elf_addr_t auxv = (elf_addr_t)ts->info->saved_auxv;
elf_addr_t orig_auxv = auxv;
- abi_ulong val;
void *ptr;
- int i, len;
+ int len = ts->info->auxv_len;
/*
* Auxiliary vector is stored in target process stack. It contains
@@ -2336,15 +2338,6 @@ static void fill_auxv_note(struct memelfnote *note, const TaskState *ts)
* strictly necessary but we do it here for sake of completeness.
*/
- /* find out length of the vector, AT_NULL is terminator */
- i = len = 0;
- do {
- get_user_ual(val, auxv);
- i += 2;
- auxv += 2 * sizeof (elf_addr_t);
- } while (val != AT_NULL);
- len = i * sizeof (elf_addr_t);
-
/* read in whole auxv vector and copy it to memelfnote */
ptr = lock_user(VERIFY_READ, orig_auxv, len, 0);
if (ptr != NULL) {
diff --git a/linux-user/main.c b/linux-user/main.c
index 64d2208a08..14bf5f0bc7 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2945,6 +2945,11 @@ static void handle_arg_log(const char *arg)
cpu_set_log(mask);
}
+static void handle_arg_log_filename(const char *arg)
+{
+ cpu_set_log_filename(arg);
+}
+
static void handle_arg_set_env(const char *arg)
{
char *r, *p, *token;
@@ -3125,6 +3130,8 @@ struct qemu_argument arg_table[] = {
#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"options", "activate log"},
+ {"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
+ "logfile", "override default logfile location"},
{"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
"pagesize", "set the host page size to 'pagesize'"},
{"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep,
diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
index 668a2b95d4..e436ea57dc 100644
--- a/linux-user/mips64/syscall.h
+++ b/linux-user/mips64/syscall.h
@@ -218,4 +218,7 @@ struct target_pt_regs {
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
#define UNAME_MACHINE "mips64"
diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h
index 4ec506cb02..ebe98f2070 100644
--- a/linux-user/mipsn32/syscall.h
+++ b/linux-user/mipsn32/syscall.h
@@ -218,4 +218,7 @@ struct target_pt_regs {
+/* Nasty hack: define a fake errno value for use by sigreturn. */
+#define TARGET_QEMU_ESIGRETURN 255
+
#define UNAME_MACHINE "mips64"
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 55ad9d8586..308dbc025b 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -48,6 +48,7 @@ struct image_info {
abi_ulong code_offset;
abi_ulong data_offset;
abi_ulong saved_auxv;
+ abi_ulong auxv_len;
abi_ulong arg_start;
abi_ulong arg_end;
int personality;
@@ -123,10 +124,10 @@ typedef struct TaskState {
#endif
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
/* Extra fields for semihosted binaries. */
- uint32_t stack_base;
uint32_t heap_base;
uint32_t heap_limit;
#endif
+ uint32_t stack_base;
int used; /* non zero if used */
struct image_info *info;
struct linux_binprm *bprm;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index ded12caa18..79a39dcd7f 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -587,7 +587,11 @@ int do_sigaction(int sig, const struct target_sigaction *act,
#endif
if (oact) {
oact->_sa_handler = tswapal(k->_sa_handler);
+#if defined(TARGET_MIPS) || defined (TARGET_ALPHA)
+ oact->sa_flags = bswap32(k->sa_flags);
+#else
oact->sa_flags = tswapal(k->sa_flags);
+#endif
#if !defined(TARGET_MIPS)
oact->sa_restorer = tswapal(k->sa_restorer);
#endif
@@ -596,7 +600,11 @@ int do_sigaction(int sig, const struct target_sigaction *act,
if (act) {
/* FIXME: This is not threadsafe. */
k->_sa_handler = tswapal(act->_sa_handler);
+#if defined(TARGET_MIPS) || defined (TARGET_ALPHA)
+ k->sa_flags = bswap32(act->sa_flags);
+#else
k->sa_flags = tswapal(act->sa_flags);
+#endif
#if !defined(TARGET_MIPS)
k->sa_restorer = tswapal(act->sa_restorer);
#endif
diff --git a/linux-user/strace.c b/linux-user/strace.c
index 90027a1106..05a0d3e9d7 100644
--- a/linux-user/strace.c
+++ b/linux-user/strace.c
@@ -1,5 +1,4 @@
#include <stdio.h>
-#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/sem.h>
@@ -284,8 +283,13 @@ print_ipc(const struct syscallname *name,
static void
print_syscall_ret_addr(const struct syscallname *name, abi_long ret)
{
-if( ret == -1 ) {
- gemu_log(" = -1 errno=%d (%s)\n", errno, target_strerror(errno));
+ char *errstr = NULL;
+
+ if (ret < 0) {
+ errstr = target_strerror(-ret);
+ }
+ if (errstr) {
+ gemu_log(" = -1 errno=%d (%s)\n", (int)-ret, errstr);
} else {
gemu_log(" = 0x" TARGET_ABI_FMT_lx "\n", ret);
}
@@ -1515,14 +1519,19 @@ void
print_syscall_ret(int num, abi_long ret)
{
int i;
+ char *errstr = NULL;
for(i=0;i<nsyscalls;i++)
if( scnames[i].nr == num ) {
if( scnames[i].result != NULL ) {
scnames[i].result(&scnames[i],ret);
} else {
- if( ret < 0 ) {
- gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n", -ret, target_strerror(-ret));
+ if (ret < 0) {
+ errstr = target_strerror(-ret);
+ }
+ if (errstr) {
+ gemu_log(" = -1 errno=" TARGET_ABI_FMT_ld " (%s)\n",
+ -ret, errstr);
} else {
gemu_log(" = " TARGET_ABI_FMT_ld "\n", ret);
}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 2bf9e7ec44..ee8899ef3d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -731,6 +731,9 @@ static inline int is_error(abi_long ret)
char *target_strerror(int err)
{
+ if ((err >= ERRNO_TABLE_SIZE) || (err < 0)) {
+ return NULL;
+ }
return strerror(target_to_host_errno(err));
}
@@ -1530,9 +1533,41 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
case TARGET_SO_LINGER:
case TARGET_SO_RCVTIMEO:
case TARGET_SO_SNDTIMEO:
- case TARGET_SO_PEERCRED:
case TARGET_SO_PEERNAME:
goto unimplemented;
+ case TARGET_SO_PEERCRED: {
+ struct ucred cr;
+ socklen_t crlen;
+ struct target_ucred *tcr;
+
+ if (get_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ if (len < 0) {
+ return -TARGET_EINVAL;
+ }
+
+ crlen = sizeof(cr);
+ ret = get_errno(getsockopt(sockfd, level, SO_PEERCRED,
+ &cr, &crlen));
+ if (ret < 0) {
+ return ret;
+ }
+ if (len > crlen) {
+ len = crlen;
+ }
+ if (!lock_user_struct(VERIFY_WRITE, tcr, optval_addr, 0)) {
+ return -TARGET_EFAULT;
+ }
+ __put_user(cr.pid, &tcr->pid);
+ __put_user(cr.uid, &tcr->uid);
+ __put_user(cr.gid, &tcr->gid);
+ unlock_user_struct(tcr, optval_addr, 1);
+ if (put_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ break;
+ }
/* Options with 'int' argument. */
case TARGET_SO_DEBUG:
optname = SO_DEBUG;
@@ -4600,6 +4635,123 @@ int get_osversion(void)
return osversion;
}
+
+static int open_self_maps(void *cpu_env, int fd)
+{
+ TaskState *ts = ((CPUState *)cpu_env)->opaque;
+
+ dprintf(fd, "%08llx-%08llx rw-p %08llx 00:00 0 [stack]\n",
+ (unsigned long long)ts->info->stack_limit,
+ (unsigned long long)(ts->stack_base + (TARGET_PAGE_SIZE - 1))
+ & TARGET_PAGE_MASK,
+ (unsigned long long)ts->stack_base);
+
+ return 0;
+}
+
+static int open_self_stat(void *cpu_env, int fd)
+{
+ TaskState *ts = ((CPUState *)cpu_env)->opaque;
+ abi_ulong start_stack = ts->info->start_stack;
+ int i;
+
+ for (i = 0; i < 44; i++) {
+ char buf[128];
+ int len;
+ uint64_t val = 0;
+
+ if (i == 27) {
+ /* stack bottom */
+ val = start_stack;
+ }
+ snprintf(buf, sizeof(buf), "%"PRId64 "%c", val, i == 43 ? '\n' : ' ');
+ len = strlen(buf);
+ if (write(fd, buf, len) != len) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int open_self_auxv(void *cpu_env, int fd)
+{
+ TaskState *ts = ((CPUState *)cpu_env)->opaque;
+ abi_ulong auxv = ts->info->saved_auxv;
+ abi_ulong len = ts->info->auxv_len;
+ char *ptr;
+
+ /*
+ * Auxiliary vector is stored in target process stack.
+ * read in whole auxv vector and copy it to file
+ */
+ ptr = lock_user(VERIFY_READ, auxv, len, 0);
+ if (ptr != NULL) {
+ while (len > 0) {
+ ssize_t r;
+ r = write(fd, ptr, len);
+ if (r <= 0) {
+ break;
+ }
+ len -= r;
+ ptr += r;
+ }
+ lseek(fd, 0, SEEK_SET);
+ unlock_user(ptr, auxv, len);
+ }
+
+ return 0;
+}
+
+static int do_open(void *cpu_env, const char *pathname, int flags, mode_t mode)
+{
+ struct fake_open {
+ const char *filename;
+ int (*fill)(void *cpu_env, int fd);
+ };
+ const struct fake_open *fake_open;
+ static const struct fake_open fakes[] = {
+ { "/proc/self/maps", open_self_maps },
+ { "/proc/self/stat", open_self_stat },
+ { "/proc/self/auxv", open_self_auxv },
+ { NULL, NULL }
+ };
+
+ for (fake_open = fakes; fake_open->filename; fake_open++) {
+ if (!strncmp(pathname, fake_open->filename,
+ strlen(fake_open->filename))) {
+ break;
+ }
+ }
+
+ if (fake_open->filename) {
+ const char *tmpdir;
+ char filename[PATH_MAX];
+ int fd, r;
+
+ /* create temporary file to map stat to */
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir)
+ tmpdir = "/tmp";
+ snprintf(filename, sizeof(filename), "%s/qemu-open.XXXXXX", tmpdir);
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ return fd;
+ }
+ unlink(filename);
+
+ if ((r = fake_open->fill(cpu_env, fd))) {
+ close(fd);
+ return r;
+ }
+ lseek(fd, 0, SEEK_SET);
+
+ return fd;
+ }
+
+ return get_errno(open(path(pathname), flags, mode));
+}
+
/* do_syscall() should always have a single exit point at the end so
that actions, such as logging of syscall results, can be performed.
All errnos that do_syscall() returns must be -TARGET_<errcode>. */
@@ -4685,9 +4837,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_open:
if (!(p = lock_user_string(arg1)))
goto efault;
- ret = get_errno(open(path(p),
- target_to_host_bitmask(arg2, fcntl_flags_tbl),
- arg3));
+ ret = get_errno(do_open(cpu_env, p,
+ target_to_host_bitmask(arg2, fcntl_flags_tbl),
+ arg3));
unlock_user(p, arg1, 0);
break;
#if defined(TARGET_NR_openat) && defined(__NR_openat)
@@ -4715,7 +4867,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
{
int status;
ret = get_errno(waitpid(arg1, &status, arg3));
- if (!is_error(ret) && arg2
+ if (!is_error(ret) && arg2 && ret
&& put_user_s32(host_to_target_waitstatus(status), arg2))
goto efault;
}
@@ -6271,7 +6423,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
rusage_ptr = NULL;
ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
if (!is_error(ret)) {
- if (status_ptr) {
+ if (status_ptr && ret) {
status = host_to_target_waitstatus(status);
if (put_user_s32(status, status_ptr))
goto efault;
@@ -7644,25 +7796,64 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
#ifdef CONFIG_ATTR
#ifdef TARGET_NR_setxattr
- case TARGET_NR_lsetxattr:
- case TARGET_NR_fsetxattr:
- case TARGET_NR_lgetxattr:
- case TARGET_NR_fgetxattr:
case TARGET_NR_listxattr:
case TARGET_NR_llistxattr:
+ {
+ void *p, *b = 0;
+ if (arg2) {
+ b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+ if (!b) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ p = lock_user_string(arg1);
+ if (p) {
+ if (num == TARGET_NR_listxattr) {
+ ret = get_errno(listxattr(p, b, arg3));
+ } else {
+ ret = get_errno(llistxattr(p, b, arg3));
+ }
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(p, arg1, 0);
+ unlock_user(b, arg2, arg3);
+ break;
+ }
case TARGET_NR_flistxattr:
- case TARGET_NR_lremovexattr:
- case TARGET_NR_fremovexattr:
- ret = -TARGET_EOPNOTSUPP;
+ {
+ void *b = 0;
+ if (arg2) {
+ b = lock_user(VERIFY_WRITE, arg2, arg3, 0);
+ if (!b) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ ret = get_errno(flistxattr(arg1, b, arg3));
+ unlock_user(b, arg2, arg3);
break;
+ }
case TARGET_NR_setxattr:
+ case TARGET_NR_lsetxattr:
{
- void *p, *n, *v;
+ void *p, *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_READ, arg3, arg4, 1);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
p = lock_user_string(arg1);
n = lock_user_string(arg2);
- v = lock_user(VERIFY_READ, arg3, arg4, 1);
- if (p && n && v) {
- ret = get_errno(setxattr(p, n, v, arg4, arg5));
+ if (p && n) {
+ if (num == TARGET_NR_setxattr) {
+ ret = get_errno(setxattr(p, n, v, arg4, arg5));
+ } else {
+ ret = get_errno(lsetxattr(p, n, v, arg4, arg5));
+ }
} else {
ret = -TARGET_EFAULT;
}
@@ -7671,14 +7862,45 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(v, arg3, 0);
}
break;
+ case TARGET_NR_fsetxattr:
+ {
+ void *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_READ, arg3, arg4, 1);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ n = lock_user_string(arg2);
+ if (n) {
+ ret = get_errno(fsetxattr(arg1, n, v, arg4, arg5));
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(n, arg2, 0);
+ unlock_user(v, arg3, 0);
+ }
+ break;
case TARGET_NR_getxattr:
+ case TARGET_NR_lgetxattr:
{
- void *p, *n, *v;
+ void *p, *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
p = lock_user_string(arg1);
n = lock_user_string(arg2);
- v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
- if (p && n && v) {
- ret = get_errno(getxattr(p, n, v, arg4));
+ if (p && n) {
+ if (num == TARGET_NR_getxattr) {
+ ret = get_errno(getxattr(p, n, v, arg4));
+ } else {
+ ret = get_errno(lgetxattr(p, n, v, arg4));
+ }
} else {
ret = -TARGET_EFAULT;
}
@@ -7687,13 +7909,38 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(v, arg3, arg4);
}
break;
+ case TARGET_NR_fgetxattr:
+ {
+ void *n, *v = 0;
+ if (arg3) {
+ v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
+ if (!v) {
+ ret = -TARGET_EFAULT;
+ break;
+ }
+ }
+ n = lock_user_string(arg2);
+ if (n) {
+ ret = get_errno(fgetxattr(arg1, n, v, arg4));
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(n, arg2, 0);
+ unlock_user(v, arg3, arg4);
+ }
+ break;
case TARGET_NR_removexattr:
+ case TARGET_NR_lremovexattr:
{
void *p, *n;
p = lock_user_string(arg1);
n = lock_user_string(arg2);
if (p && n) {
- ret = get_errno(removexattr(p, n));
+ if (num == TARGET_NR_removexattr) {
+ ret = get_errno(removexattr(p, n));
+ } else {
+ ret = get_errno(lremovexattr(p, n));
+ }
} else {
ret = -TARGET_EFAULT;
}
@@ -7701,6 +7948,18 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
unlock_user(n, arg2, 0);
}
break;
+ case TARGET_NR_fremovexattr:
+ {
+ void *n;
+ n = lock_user_string(arg2);
+ if (n) {
+ ret = get_errno(fremovexattr(arg1, n));
+ } else {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(n, arg2, 0);
+ }
+ break;
#endif
#endif /* CONFIG_ATTR */
#ifdef TARGET_NR_set_thread_area
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 2857805e16..41f0ff8c7d 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2336,3 +2336,9 @@ struct target_rlimit64 {
uint64_t rlim_cur;
uint64_t rlim_max;
};
+
+struct target_ucred {
+ uint32_t pid;
+ uint32_t uid;
+ uint32_t gid;
+};
diff --git a/main-loop.c b/main-loop.c
index 692381cb19..db23de0497 100644
--- a/main-loop.c
+++ b/main-loop.c
@@ -164,7 +164,7 @@ static int qemu_signal_init(void)
#else /* _WIN32 */
-HANDLE qemu_event_handle;
+HANDLE qemu_event_handle = NULL;
static void dummy_event_handler(void *opaque)
{
@@ -183,6 +183,9 @@ static int qemu_event_init(void)
void qemu_notify_event(void)
{
+ if (!qemu_event_handle) {
+ return;
+ }
if (!SetEvent(qemu_event_handle)) {
fprintf(stderr, "qemu_notify_event: SetEvent failed: %ld\n",
GetLastError());
@@ -196,7 +199,7 @@ static int qemu_signal_init(void)
}
#endif
-int qemu_init_main_loop(void)
+int main_loop_init(void)
{
int ret;
diff --git a/main-loop.h b/main-loop.h
index f9710136c9..4987041ce7 100644
--- a/main-loop.h
+++ b/main-loop.h
@@ -41,10 +41,22 @@
* SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time
* signals if available. Remember that Windows in practice does not have
* signals, though.
+ *
+ * In the case of QEMU tools, this will also start/initialize timers.
*/
int qemu_init_main_loop(void);
/**
+ * main_loop_init: Initializes main loop
+ *
+ * Internal (but shared for compatibility reasons) initialization routine
+ * for the main loop. This should not be used by applications directly,
+ * use qemu_init_main_loop() instead.
+ *
+ */
+int main_loop_init(void);
+
+/**
* main_loop_wait: Run one iteration of the main loop.
*
* If @nonblocking is true, poll for events, otherwise suspend until
diff --git a/memory.c b/memory.c
index 6201a3749a..5e77d8a2f4 100644
--- a/memory.c
+++ b/memory.c
@@ -1049,6 +1049,42 @@ void memory_region_init_rom_device(MemoryRegion *mr,
mr->ram_addr |= cpu_register_io_memory(mr);
}
+static uint64_t invalid_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ MemoryRegion *mr = opaque;
+
+ if (!mr->warning_printed) {
+ fprintf(stderr, "Invalid read from memory region %s\n", mr->name);
+ mr->warning_printed = true;
+ }
+ return -1U;
+}
+
+static void invalid_write(void *opaque, target_phys_addr_t addr, uint64_t data,
+ unsigned size)
+{
+ MemoryRegion *mr = opaque;
+
+ if (!mr->warning_printed) {
+ fprintf(stderr, "Invalid write to memory region %s\n", mr->name);
+ mr->warning_printed = true;
+ }
+}
+
+static const MemoryRegionOps reservation_ops = {
+ .read = invalid_read,
+ .write = invalid_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void memory_region_init_reservation(MemoryRegion *mr,
+ const char *name,
+ uint64_t size)
+{
+ memory_region_init_io(mr, &reservation_ops, mr, name, size);
+}
+
void memory_region_destroy(MemoryRegion *mr)
{
assert(QTAILQ_EMPTY(&mr->subregions));
@@ -1100,16 +1136,18 @@ void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
}
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
- unsigned client)
+ target_phys_addr_t size, unsigned client)
{
assert(mr->terminates);
- return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
+ return cpu_physical_memory_get_dirty(mr->ram_addr + addr, size,
+ 1 << client);
}
-void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr)
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+ target_phys_addr_t size)
{
assert(mr->terminates);
- return cpu_physical_memory_set_dirty(mr->ram_addr + addr);
+ return cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size, -1);
}
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
diff --git a/memory.h b/memory.h
index d48b08bf94..4cf8d2f27a 100644
--- a/memory.h
+++ b/memory.h
@@ -126,6 +126,7 @@ struct MemoryRegion {
bool readonly; /* For RAM regions */
bool enabled;
bool rom_device;
+ bool warning_printed; /* For reservations */
MemoryRegion *alias;
target_phys_addr_t alias_offset;
unsigned priority;
@@ -280,6 +281,21 @@ void memory_region_init_rom_device(MemoryRegion *mr,
uint64_t size);
/**
+ * memory_region_init_reservation: Initialize a memory region that reserves
+ * I/O space.
+ *
+ * A reservation region primariy serves debugging purposes. It claims I/O
+ * space that is not supposed to be handled by QEMU itself. Any access via
+ * the memory API will cause an abort().
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @name: used for debugging; not visible to the user or ABI
+ * @size: size of the region.
+ */
+void memory_region_init_reservation(MemoryRegion *mr,
+ const char *name,
+ uint64_t size);
+/**
* memory_region_destroy: Destroy a memory region and reclaim all resources.
*
* @mr: the region to be destroyed. May not currently be a subregion
@@ -364,30 +380,34 @@ void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset);
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client);
/**
- * memory_region_get_dirty: Check whether a page is dirty for a specified
- * client.
+ * memory_region_get_dirty: Check whether a range of bytes is dirty
+ * for a specified client.
*
- * Checks whether a page has been written to since the last
+ * Checks whether a range of bytes has been written to since the last
* call to memory_region_reset_dirty() with the same @client. Dirty logging
* must be enabled.
*
* @mr: the memory region being queried.
* @addr: the address (relative to the start of the region) being queried.
+ * @size: the size of the range being queried.
* @client: the user of the logging information; %DIRTY_MEMORY_MIGRATION or
* %DIRTY_MEMORY_VGA.
*/
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
- unsigned client);
+ target_phys_addr_t size, unsigned client);
/**
- * memory_region_set_dirty: Mark a page as dirty in a memory region.
+ * memory_region_set_dirty: Mark a range of bytes as dirty in a memory region.
*
- * Marks a page as dirty, after it has been dirtied outside guest code.
+ * Marks a range of bytes as dirty, after it has been dirtied outside
+ * guest code.
*
- * @mr: the memory region being queried.
+ * @mr: the memory region being dirtied.
* @addr: the address (relative to the start of the region) being dirtied.
+ * @size: size of the range being dirtied.
*/
-void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr);
+void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr,
+ target_phys_addr_t size);
/**
* memory_region_sync_dirty_bitmap: Synchronize a region's dirty bitmap with
diff --git a/monitor.c b/monitor.c
index 733440115f..aadbdcbf33 100644
--- a/monitor.c
+++ b/monitor.c
@@ -227,7 +227,7 @@ int monitor_cur_is_qmp(void)
return cur_mon && monitor_ctrl_mode(cur_mon);
}
-static void monitor_read_command(Monitor *mon, int show_prompt)
+void monitor_read_command(Monitor *mon, int show_prompt)
{
if (!mon->rs)
return;
@@ -237,8 +237,8 @@ static void monitor_read_command(Monitor *mon, int show_prompt)
readline_show_prompt(mon->rs);
}
-static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
- void *opaque)
+int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+ void *opaque)
{
if (monitor_ctrl_mode(mon)) {
qerror_report(QERR_MISSING_PARAMETER, "password");
@@ -479,6 +479,12 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
case QEVENT_SPICE_DISCONNECTED:
event_name = "SPICE_DISCONNECTED";
break;
+ case QEVENT_BLOCK_JOB_COMPLETED:
+ event_name = "BLOCK_JOB_COMPLETED";
+ break;
+ case QEVENT_BLOCK_JOB_CANCELLED:
+ event_name = "BLOCK_JOB_CANCELLED";
+ break;
default:
abort();
break;
@@ -810,171 +816,6 @@ static void do_trace_print_events(Monitor *mon)
trace_print_events((FILE *)mon, &monitor_fprintf);
}
-#ifdef CONFIG_VNC
-static int change_vnc_password(const char *password)
-{
- if (!password || !password[0]) {
- if (vnc_display_disable_login(NULL)) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
- return 0;
- }
-
- if (vnc_display_password(NULL, password) < 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
-
- return 0;
-}
-
-static void change_vnc_password_cb(Monitor *mon, const char *password,
- void *opaque)
-{
- change_vnc_password(password);
- monitor_read_command(mon, 1);
-}
-
-static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
-{
- if (strcmp(target, "passwd") == 0 ||
- strcmp(target, "password") == 0) {
- if (arg) {
- char password[9];
- strncpy(password, arg, sizeof(password));
- password[sizeof(password) - 1] = '\0';
- return change_vnc_password(password);
- } else {
- return monitor_read_password(mon, change_vnc_password_cb, NULL);
- }
- } else {
- if (vnc_display_open(NULL, target) < 0) {
- qerror_report(QERR_VNC_SERVER_FAILED, target);
- return -1;
- }
- }
-
- return 0;
-}
-#else
-static int do_change_vnc(Monitor *mon, const char *target, const char *arg)
-{
- qerror_report(QERR_FEATURE_DISABLED, "vnc");
- return -ENODEV;
-}
-#endif
-
-/**
- * do_change(): Change a removable medium, or VNC configuration
- */
-static int do_change(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *device = qdict_get_str(qdict, "device");
- const char *target = qdict_get_str(qdict, "target");
- const char *arg = qdict_get_try_str(qdict, "arg");
- int ret;
-
- if (strcmp(device, "vnc") == 0) {
- ret = do_change_vnc(mon, target, arg);
- } else {
- ret = do_change_block(mon, device, target, arg);
- }
-
- return ret;
-}
-
-static int set_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *protocol = qdict_get_str(qdict, "protocol");
- const char *password = qdict_get_str(qdict, "password");
- const char *connected = qdict_get_try_str(qdict, "connected");
- int disconnect_if_connected = 0;
- int fail_if_connected = 0;
- int rc;
-
- if (connected) {
- if (strcmp(connected, "fail") == 0) {
- fail_if_connected = 1;
- } else if (strcmp(connected, "disconnect") == 0) {
- disconnect_if_connected = 1;
- } else if (strcmp(connected, "keep") == 0) {
- /* nothing */
- } else {
- qerror_report(QERR_INVALID_PARAMETER, "connected");
- return -1;
- }
- }
-
- if (strcmp(protocol, "spice") == 0) {
- if (!using_spice) {
- /* correct one? spice isn't a device ,,, */
- qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
- return -1;
- }
- rc = qemu_spice_set_passwd(password, fail_if_connected,
- disconnect_if_connected);
- if (rc != 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
- return 0;
- }
-
- if (strcmp(protocol, "vnc") == 0) {
- if (fail_if_connected || disconnect_if_connected) {
- /* vnc supports "connected=keep" only */
- qerror_report(QERR_INVALID_PARAMETER, "connected");
- return -1;
- }
- /* Note that setting an empty password will not disable login through
- * this interface. */
- return vnc_display_password(NULL, password);
- }
-
- qerror_report(QERR_INVALID_PARAMETER, "protocol");
- return -1;
-}
-
-static int expire_password(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- const char *protocol = qdict_get_str(qdict, "protocol");
- const char *whenstr = qdict_get_str(qdict, "time");
- time_t when;
- int rc;
-
- if (strcmp(whenstr, "now") == 0) {
- when = 0;
- } else if (strcmp(whenstr, "never") == 0) {
- when = TIME_MAX;
- } else if (whenstr[0] == '+') {
- when = time(NULL) + strtoull(whenstr+1, NULL, 10);
- } else {
- when = strtoull(whenstr, NULL, 10);
- }
-
- if (strcmp(protocol, "spice") == 0) {
- if (!using_spice) {
- /* correct one? spice isn't a device ,,, */
- qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice");
- return -1;
- }
- rc = qemu_spice_set_pw_expire(when);
- if (rc != 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- return -1;
- }
- return 0;
- }
-
- if (strcmp(protocol, "vnc") == 0) {
- return vnc_display_pw_expire(NULL, when);
- }
-
- qerror_report(QERR_INVALID_PARAMETER, "protocol");
- return -1;
-}
-
static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *protocol = qdict_get_str(qdict, "protocol");
@@ -2477,6 +2318,13 @@ static mon_cmd_t info_cmds[] = {
.mhandler.info = hmp_info_blockstats,
},
{
+ .name = "block-jobs",
+ .args_type = "",
+ .params = "",
+ .help = "show progress of ongoing block device operations",
+ .mhandler.info = hmp_info_block_jobs,
+ },
+ {
.name = "registers",
.args_type = "",
.params = "",
@@ -4755,6 +4603,11 @@ static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
monitor_read_command(mon, 1);
}
+ReadLineState *monitor_get_rs(Monitor *mon)
+{
+ return mon->rs;
+}
+
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
BlockDriverCompletionFunc *completion_cb,
void *opaque)
@@ -4768,7 +4621,8 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
}
if (monitor_ctrl_mode(mon)) {
- qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+ qerror_report(QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+ bdrv_get_encrypted_filename(bs));
return -1;
}
diff --git a/monitor.h b/monitor.h
index cfa2f679f4..b72ea07050 100644
--- a/monitor.h
+++ b/monitor.h
@@ -6,6 +6,7 @@
#include "qerror.h"
#include "qdict.h"
#include "block.h"
+#include "readline.h"
extern Monitor *cur_mon;
extern Monitor *default_mon;
@@ -35,6 +36,8 @@ typedef enum MonitorEvent {
QEVENT_SPICE_CONNECTED,
QEVENT_SPICE_INITIALIZED,
QEVENT_SPICE_DISCONNECTED,
+ QEVENT_BLOCK_JOB_COMPLETED,
+ QEVENT_BLOCK_JOB_CANCELLED,
QEVENT_MAX,
} MonitorEvent;
@@ -66,6 +69,10 @@ int monitor_get_cpu_index(void);
typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
void monitor_set_error(Monitor *mon, QError *qerror);
+void monitor_read_command(Monitor *mon, int show_prompt);
+ReadLineState *monitor_get_rs(Monitor *mon);
+int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+ void *opaque);
int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret);
diff --git a/net.c b/net.c
index 2b0f766408..c34474fe5f 100644
--- a/net.c
+++ b/net.c
@@ -38,6 +38,11 @@
#include "hw/qdev.h"
#include "iov.h"
+/* Net bridge is currently not supported for W32. */
+#if !defined(_WIN32)
+# define CONFIG_NET_BRIDGE
+#endif
+
static QTAILQ_HEAD(, VLANState) vlans;
static QTAILQ_HEAD(, VLANClientState) non_vlan_clients;
@@ -952,6 +957,12 @@ static const struct {
.type = QEMU_OPT_STRING,
.help = "script to shut down the interface",
}, {
+#ifdef CONFIG_NET_BRIDGE
+ .name = "helper",
+ .type = QEMU_OPT_STRING,
+ .help = "command to execute to configure bridge",
+ }, {
+#endif
.name = "sndbuf",
.type = QEMU_OPT_SIZE,
.help = "send buffer limit"
@@ -1053,6 +1064,25 @@ static const struct {
{ /* end of list */ }
},
},
+#ifdef CONFIG_NET_BRIDGE
+ [NET_CLIENT_TYPE_BRIDGE] = {
+ .type = "bridge",
+ .init = net_init_bridge,
+ .desc = {
+ NET_COMMON_PARAMS_DESC,
+ {
+ .name = "br",
+ .type = QEMU_OPT_STRING,
+ .help = "bridge name",
+ }, {
+ .name = "helper",
+ .type = QEMU_OPT_STRING,
+ .help = "command to execute to configure bridge",
+ },
+ { /* end of list */ }
+ },
+ },
+#endif /* CONFIG_NET_BRIDGE */
};
int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
@@ -1069,6 +1099,9 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
if (is_netdev) {
if (strcmp(type, "tap") != 0 &&
+#ifdef CONFIG_NET_BRIDGE
+ strcmp(type, "bridge") != 0 &&
+#endif
#ifdef CONFIG_SLIRP
strcmp(type, "user") != 0 &&
#endif
@@ -1139,6 +1172,9 @@ static int net_host_check_device(const char *device)
{
int i;
const char *valid_param_list[] = { "tap", "socket", "dump"
+#ifdef CONFIG_NET_BRIDGE
+ , "bridge"
+#endif
#ifdef CONFIG_SLIRP
,"user"
#endif
diff --git a/net.h b/net.h
index eab089d577..75a8c155e5 100644
--- a/net.h
+++ b/net.h
@@ -37,6 +37,7 @@ typedef enum {
NET_CLIENT_TYPE_SOCKET,
NET_CLIENT_TYPE_VDE,
NET_CLIENT_TYPE_DUMP,
+ NET_CLIENT_TYPE_BRIDGE,
NET_CLIENT_TYPE_MAX
} net_client_type;
@@ -174,6 +175,8 @@ int do_netdev_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
+#define DEFAULT_BRIDGE_HELPER CONFIG_QEMU_HELPERDIR "/qemu-bridge-helper"
+#define DEFAULT_BRIDGE_INTERFACE "br0"
void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd);
diff --git a/net/checksum.c b/net/checksum.c
index 264c23fe4f..9919b2e5fd 100644
--- a/net/checksum.c
+++ b/net/checksum.c
@@ -4,7 +4,7 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; under version 2 of the License.
+ * the Free Software Foundation; under version 2 or later of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -13,9 +13,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Contributions after 2012-01-13 are licensed under the terms of the
- * GNU GPL, version 2 or (at your option) any later version.
*/
#include "net/checksum.h"
diff --git a/net/tap.c b/net/tap.c
index 6c27a9427f..f2400283c3 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -382,6 +382,171 @@ static int launch_script(const char *setup_script, const char *ifname, int fd)
return -1;
}
+static int recv_fd(int c)
+{
+ int fd;
+ uint8_t msgbuf[CMSG_SPACE(sizeof(fd))];
+ struct msghdr msg = {
+ .msg_control = msgbuf,
+ .msg_controllen = sizeof(msgbuf),
+ };
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ uint8_t req[1];
+ ssize_t len;
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ iov.iov_base = req;
+ iov.iov_len = sizeof(req);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ len = recvmsg(c, &msg, 0);
+ if (len > 0) {
+ memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd));
+ return fd;
+ }
+
+ return len;
+}
+
+static int net_bridge_run_helper(const char *helper, const char *bridge)
+{
+ sigset_t oldmask, mask;
+ int pid, status;
+ char *args[5];
+ char **parg;
+ int sv[2];
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &oldmask);
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+ return -1;
+ }
+
+ /* try to launch bridge helper */
+ pid = fork();
+ if (pid == 0) {
+ int open_max = sysconf(_SC_OPEN_MAX), i;
+ char fd_buf[6+10];
+ char br_buf[6+IFNAMSIZ] = {0};
+ char helper_cmd[PATH_MAX + sizeof(fd_buf) + sizeof(br_buf) + 15];
+
+ for (i = 0; i < open_max; i++) {
+ if (i != STDIN_FILENO &&
+ i != STDOUT_FILENO &&
+ i != STDERR_FILENO &&
+ i != sv[1]) {
+ close(i);
+ }
+ }
+
+ snprintf(fd_buf, sizeof(fd_buf), "%s%d", "--fd=", sv[1]);
+
+ if (strrchr(helper, ' ') || strrchr(helper, '\t')) {
+ /* assume helper is a command */
+
+ if (strstr(helper, "--br=") == NULL) {
+ snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
+ }
+
+ snprintf(helper_cmd, sizeof(helper_cmd), "%s %s %s %s",
+ helper, "--use-vnet", fd_buf, br_buf);
+
+ parg = args;
+ *parg++ = (char *)"sh";
+ *parg++ = (char *)"-c";
+ *parg++ = helper_cmd;
+ *parg++ = NULL;
+
+ execv("/bin/sh", args);
+ } else {
+ /* assume helper is just the executable path name */
+
+ snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge);
+
+ parg = args;
+ *parg++ = (char *)helper;
+ *parg++ = (char *)"--use-vnet";
+ *parg++ = fd_buf;
+ *parg++ = br_buf;
+ *parg++ = NULL;
+
+ execv(helper, args);
+ }
+ _exit(1);
+
+ } else if (pid > 0) {
+ int fd;
+
+ close(sv[1]);
+
+ do {
+ fd = recv_fd(sv[0]);
+ } while (fd == -1 && errno == EINTR);
+
+ close(sv[0]);
+
+ while (waitpid(pid, &status, 0) != pid) {
+ /* loop */
+ }
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ if (fd < 0) {
+ fprintf(stderr, "failed to recv file descriptor\n");
+ return -1;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ return fd;
+ }
+ }
+ fprintf(stderr, "failed to launch bridge helper\n");
+ return -1;
+}
+
+int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name,
+ VLANState *vlan)
+{
+ TAPState *s;
+ int fd, vnet_hdr;
+
+ if (!qemu_opt_get(opts, "br")) {
+ qemu_opt_set(opts, "br", DEFAULT_BRIDGE_INTERFACE);
+ }
+ if (!qemu_opt_get(opts, "helper")) {
+ qemu_opt_set(opts, "helper", DEFAULT_BRIDGE_HELPER);
+ }
+
+ fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
+ qemu_opt_get(opts, "br"));
+ if (fd == -1) {
+ return -1;
+ }
+
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ vnet_hdr = tap_probe_vnet_hdr(fd);
+
+ s = net_tap_fd_init(vlan, "bridge", name, fd, vnet_hdr);
+ if (!s) {
+ close(fd);
+ return -1;
+ }
+
+ snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s",
+ qemu_opt_get(opts, "helper"), qemu_opt_get(opts, "br"));
+
+ return 0;
+}
+
static int net_tap_init(QemuOpts *opts, int *vnet_hdr)
{
int fd, vnet_hdr_required;
@@ -422,13 +587,16 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
{
TAPState *s;
int fd, vnet_hdr = 0;
+ const char *model;
if (qemu_opt_get(opts, "fd")) {
if (qemu_opt_get(opts, "ifname") ||
qemu_opt_get(opts, "script") ||
qemu_opt_get(opts, "downscript") ||
- qemu_opt_get(opts, "vnet_hdr")) {
- error_report("ifname=, script=, downscript= and vnet_hdr= is invalid with fd=");
+ qemu_opt_get(opts, "vnet_hdr") ||
+ qemu_opt_get(opts, "helper")) {
+ error_report("ifname=, script=, downscript=, vnet_hdr=, "
+ "and helper= are invalid with fd=");
return -1;
}
@@ -440,6 +608,31 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
fcntl(fd, F_SETFL, O_NONBLOCK);
vnet_hdr = tap_probe_vnet_hdr(fd);
+
+ model = "tap";
+
+ } else if (qemu_opt_get(opts, "helper")) {
+ if (qemu_opt_get(opts, "ifname") ||
+ qemu_opt_get(opts, "script") ||
+ qemu_opt_get(opts, "downscript") ||
+ qemu_opt_get(opts, "vnet_hdr")) {
+ error_report("ifname=, script=, downscript=, and vnet_hdr= "
+ "are invalid with helper=");
+ return -1;
+ }
+
+ fd = net_bridge_run_helper(qemu_opt_get(opts, "helper"),
+ DEFAULT_BRIDGE_INTERFACE);
+ if (fd == -1) {
+ return -1;
+ }
+
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ vnet_hdr = tap_probe_vnet_hdr(fd);
+
+ model = "bridge";
+
} else {
if (!qemu_opt_get(opts, "script")) {
qemu_opt_set(opts, "script", DEFAULT_NETWORK_SCRIPT);
@@ -453,9 +646,11 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
if (fd == -1) {
return -1;
}
+
+ model = "tap";
}
- s = net_tap_fd_init(vlan, "tap", name, fd, vnet_hdr);
+ s = net_tap_fd_init(vlan, model, name, fd, vnet_hdr);
if (!s) {
close(fd);
return -1;
@@ -467,6 +662,9 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
if (qemu_opt_get(opts, "fd")) {
snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
+ } else if (qemu_opt_get(opts, "helper")) {
+ snprintf(s->nc.info_str, sizeof(s->nc.info_str),
+ "helper=%s", qemu_opt_get(opts, "helper"));
} else {
const char *ifname, *script, *downscript;
diff --git a/net/tap.h b/net/tap.h
index e44bd2bc5f..56c591fc8e 100644
--- a/net/tap.h
+++ b/net/tap.h
@@ -57,4 +57,7 @@ int tap_get_fd(VLANClientState *vc);
struct vhost_net;
struct vhost_net *tap_get_vhost_net(VLANClientState *vc);
+int net_init_bridge(QemuOpts *opts, Monitor *mon, const char *name,
+ VLANState *vlan);
+
#endif /* QEMU_NET_TAP_H */
diff --git a/os-posix.c b/os-posix.c
index 5c437ca12c..e3ed497224 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -348,6 +348,6 @@ int qemu_create_pidfile(const char *filename)
return -1;
}
- close(fd);
+ /* keep pidfile open & locked forever */
return 0;
}
diff --git a/pc-bios/README b/pc-bios/README
index 1cebbbc89a..5dce355f56 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/dgibson/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20111013.
+ built from git tag qemu-slof-20120111.1.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/bamboo.dtb b/pc-bios/bamboo.dtb
index c78e2544c0..d12e201aa0 100644
--- a/pc-bios/bamboo.dtb
+++ b/pc-bios/bamboo.dtb
Binary files differ
diff --git a/pc-bios/bamboo.dts b/pc-bios/bamboo.dts
index 655442ca69..62fabcca68 100644
--- a/pc-bios/bamboo.dts
+++ b/pc-bios/bamboo.dts
@@ -9,12 +9,14 @@
* any warranty of any kind, whether express or implied.
*/
+/dts-v1/;
+
/ {
#address-cells = <2>;
#size-cells = <1>;
model = "amcc,bamboo";
compatible = "amcc,bamboo";
- dcr-parent = <&/cpus/cpu@0>;
+ dcr-parent = <&{/cpus/cpu@0}>;
aliases {
serial0 = &UART0;
@@ -29,12 +31,12 @@
device_type = "cpu";
model = "PowerPC,440EP";
reg = <0>;
- clock-frequency = <1fca0550>;
- timebase-frequency = <017d7840>;
- i-cache-line-size = <20>;
- d-cache-line-size = <20>;
- i-cache-size = <8000>;
- d-cache-size = <8000>;
+ clock-frequency = <0x1fca0550>;
+ timebase-frequency = <0x017d7840>;
+ i-cache-line-size = <0x20>;
+ d-cache-line-size = <0x20>;
+ i-cache-size = <0x8000>;
+ d-cache-size = <0x8000>;
dcr-controller;
dcr-access-method = "native";
};
@@ -42,40 +44,27 @@
memory {
device_type = "memory";
- reg = <0 0 9000000>;
+ reg = <0x0 0x0 0x9000000>;
};
UIC0: interrupt-controller0 {
compatible = "ibm,uic-440ep","ibm,uic";
interrupt-controller;
- cell-index = <0>;
- dcr-reg = <0c0 009>;
- #address-cells = <0>;
- #size-cells = <0>;
- #interrupt-cells = <2>;
- };
-/*
- UIC1: interrupt-controller1 {
- compatible = "ibm,uic-440ep","ibm,uic";
- interrupt-controller;
- cell-index = <1>;
- dcr-reg = <0d0 009>;
- #address-cells = <0>;
- #size-cells = <0>;
- #interrupt-cells = <2>;
- interrupts = <1e 4 1f 4>;
- interrupt-parent = <&UIC0>;
+ cell-index = <0x0>;
+ dcr-reg = <0x0c0 0x009>;
+ #address-cells = <0x0>;
+ #size-cells = <0x0>;
+ #interrupt-cells = <0x2>;
};
-*/
SDR0: sdr {
compatible = "ibm,sdr-440ep";
- dcr-reg = <00e 002>;
+ dcr-reg = <0x00e 0x002>;
};
CPR0: cpr {
compatible = "ibm,cpr-440ep";
- dcr-reg = <00c 002>;
+ dcr-reg = <0x00c 0x002>;
};
plb {
@@ -83,16 +72,16 @@
#address-cells = <2>;
#size-cells = <1>;
ranges;
- clock-frequency = <07f28154>;
+ clock-frequency = <0x07f28154>;
SDRAM0: sdram {
compatible = "ibm,sdram-440ep", "ibm,sdram-405gp";
- dcr-reg = <010 2>;
+ dcr-reg = <0x010 0x2>;
};
DMA0: dma {
compatible = "ibm,dma-440ep", "ibm,dma-440gp";
- dcr-reg = <100 027>;
+ dcr-reg = <0x100 0x027>;
};
POB0: opb {
@@ -102,18 +91,18 @@
/* Bamboo is oddball in the 44x world and doesn't use the ERPN
* bits.
*/
- ranges = <00000000 0 00000000 80000000
- 80000000 0 80000000 80000000>;
+ ranges = <0x00000000 0x0 0x00000000 0x80000000
+ 0x80000000 0x0 0x80000000 0x80000000>;
/* interrupt-parent = <&UIC1>; */
interrupts = <7 4>;
- clock-frequency = <03f940aa>;
+ clock-frequency = <0x03f940aa>;
EBC0: ebc {
compatible = "ibm,ebc-440ep", "ibm,ebc-440gp", "ibm,ebc";
- dcr-reg = <012 2>;
+ dcr-reg = <0x012 2>;
#address-cells = <2>;
#size-cells = <1>;
- clock-frequency = <03f940aa>;
+ clock-frequency = <0x03f940aa>;
interrupts = <5 1>;
/* interrupt-parent = <&UIC1>; */
};
@@ -121,10 +110,10 @@
UART0: serial@ef600300 {
device_type = "serial";
compatible = "ns16550";
- reg = <ef600300 8>;
- virtual-reg = <ef600300>;
- clock-frequency = <00a8c000>;
- current-speed = <1c200>;
+ reg = <0xef600300 8>;
+ virtual-reg = <0xef600300>;
+ clock-frequency = <0x00a8c000>;
+ current-speed = <0x1c200>;
interrupt-parent = <&UIC0>;
interrupts = <0 4>;
};
@@ -132,41 +121,18 @@
UART1: serial@ef600400 {
device_type = "serial";
compatible = "ns16550";
- reg = <ef600400 8>;
- virtual-reg = <ef600400>;
- clock-frequency = <00a8c000>;
+ reg = <0xef600400 8>;
+ virtual-reg = <0xef600400>;
+ clock-frequency = <0x00a8c000>;
current-speed = <0>;
interrupt-parent = <&UIC0>;
interrupts = <1 4>;
};
-/*
- UART2: serial@ef600500 {
- device_type = "serial";
- compatible = "ns16550";
- reg = <ef600500 8>;
- virtual-reg = <ef600500>;
- clock-frequency = <0>;
- current-speed = <0>;
- interrupt-parent = <&UIC0>;
- interrupts = <3 4>;
- };
-
- UART3: serial@ef600600 {
- device_type = "serial";
- compatible = "ns16550";
- reg = <ef600600 8>;
- virtual-reg = <ef600600>;
- clock-frequency = <0>;
- current-speed = <0>;
- interrupt-parent = <&UIC0>;
- interrupts = <4 4>;
- };
-*/
IIC0: i2c@ef600700 {
device_type = "i2c";
compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
- reg = <ef600700 14>;
+ reg = <0xef600700 0x14>;
interrupt-parent = <&UIC0>;
interrupts = <2 4>;
};
@@ -174,7 +140,7 @@
IIC1: i2c@ef600800 {
device_type = "i2c";
compatible = "ibm,iic-440ep", "ibm,iic-440gp", "ibm,iic";
- reg = <ef600800 14>;
+ reg = <0xef600800 14>;
interrupt-parent = <&UIC0>;
interrupts = <7 4>;
};
@@ -182,7 +148,7 @@
ZMII0: emac-zmii@ef600d00 {
device_type = "zmii-interface";
compatible = "ibm,zmii-440ep", "ibm,zmii-440gp", "ibm,zmii";
- reg = <ef600d00 c>;
+ reg = <0xef600d00 0xc>;
};
};
@@ -194,35 +160,35 @@
#address-cells = <3>;
compatible = "ibm,plb440ep-pci", "ibm,plb-pci";
primary;
- reg = <0 eec00000 8 /* Config space access */
- 0 eed00000 4 /* IACK */
- 0 eed00000 4 /* Special cycle */
- 0 ef400000 40>; /* Internal registers */
+ reg = <0 0xeec00000 8 /* Config space access */
+ 0 0xeed00000 4 /* IACK */
+ 0 0xeed00000 4 /* Special cycle */
+ 0 0xef400000 0x40>; /* Internal registers */
/* Outbound ranges, one memory and one IO,
* later cannot be changed. Chip supports a second
* IO range but we don't use it for now
*/
- ranges = <02000000 0 a0000000 0 a0000000 0 20000000
- 01000000 0 00000000 0 e8000000 0 00010000>;
+ ranges = <0x02000000 0 0xa0000000 0 0xa0000000 0 0x20000000
+ 0x01000000 0 0x00000000 0 0xe8000000 0 0x00010000>;
/* Inbound 2GB range starting at 0 */
- dma-ranges = <42000000 0 0 0 0 0 80000000>;
+ dma-ranges = <0x42000000 0 0 0 0 0 0x80000000>;
/* Bamboo has all 4 IRQ pins tied together per slot */
- interrupt-map-mask = <f800 0 0 0>;
+ interrupt-map-mask = <0xf800 0 0 0>;
interrupt-map = <
/* IDSEL 1 */
- 0800 0 0 0 &UIC0 1c 8
+ 0x0800 0 0 0 &UIC0 0x1c 8
/* IDSEL 2 */
- 1000 0 0 0 &UIC0 1b 8
+ 0x1000 0 0 0 &UIC0 0x1b 8
/* IDSEL 3 */
- 1800 0 0 0 &UIC0 1a 8
+ 0x1800 0 0 0 &UIC0 0x1a 8
/* IDSEL 4 */
- 2000 0 0 0 &UIC0 19 8
+ 0x2000 0 0 0 &UIC0 0x19 8
>;
};
diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index 51da288e32..2caf7e6b69 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -16,6 +16,9 @@ QEMU_CFLAGS = $(CFLAGS)
build-all: multiboot.bin linuxboot.bin
+# suppress auto-removal of intermediate files
+.SECONDARY:
+
%.img: %.o
$(call quiet-command,$(LD) -Ttext 0 -e _start -s -o $@ $<," Building $(TARGET_DIR)$@")
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 1e84582cc6..8554f54b57 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/qapi-schema.json b/qapi-schema.json
index 44cf764ec3..d02ee867a5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -845,6 +845,38 @@
{ 'command': 'query-pci', 'returns': ['PciInfo'] }
##
+# @BlockJobInfo:
+#
+# Information about a long-running block device operation.
+#
+# @type: the job type ('stream' for image streaming)
+#
+# @device: the block device name
+#
+# @len: the maximum progress value
+#
+# @offset: the current progress value
+#
+# @speed: the rate limit, bytes per second
+#
+# Since: 1.1
+##
+{ 'type': 'BlockJobInfo',
+ 'data': {'type': 'str', 'device': 'str', 'len': 'int',
+ 'offset': 'int', 'speed': 'int'} }
+
+##
+# @query-block-jobs:
+#
+# Return information about long-running block device operations.
+#
+# Returns: a list of @BlockJobInfo for each active block job
+#
+# Since: 1.1
+##
+{ 'command': 'query-block-jobs', 'returns': ['BlockJobInfo'] }
+
+##
# @quit:
#
# This command will cause the QEMU process to exit gracefully. While every
@@ -1064,8 +1096,11 @@
#
# Returns: nothing on success
# If @device is not a valid block device, DeviceNotFound
-#
-# Notes: This command returns UndefinedError in a number of error conditions.
+# If @size is negative, InvalidParameterValue
+# If the block device has no medium inserted, DeviceHasNoMedium
+# If the block device does not support resize, Unsupported
+# If the block device is read-only, DeviceIsReadOnly
+# If a long-running operation is using the device, DeviceInUse
#
# Since: 0.14.0
##
@@ -1193,20 +1228,20 @@
#
# Notes: This type is experimental. Its syntax may change in future releases.
##
-{ 'type': 'DevicePropertyInfo',
+{ 'type': 'ObjectPropertyInfo',
'data': { 'name': 'str', 'type': 'str' } }
##
# @qom-list:
#
-# This command will list any properties of a device given a path in the device
+# This command will list any properties of a object given a path in the object
# model.
#
-# @path: the path within the device model. See @qom-get for a description of
+# @path: the path within the object model. See @qom-get for a description of
# this parameter.
#
-# Returns: a list of @DevicePropertyInfo that describe the properties of the
-# device.
+# Returns: a list of @ObjectPropertyInfo that describe the properties of the
+# object.
#
# Since: 1.1
#
@@ -1215,25 +1250,25 @@
##
{ 'command': 'qom-list',
'data': { 'path': 'str' },
- 'returns': [ 'DevicePropertyInfo' ] }
+ 'returns': [ 'ObjectPropertyInfo' ] }
##
# @qom-get:
#
-# This command will get a property from a device model path and return the
+# This command will get a property from a object model path and return the
# value.
#
-# @path: The path within the device model. There are two forms of supported
+# @path: The path within the object model. There are two forms of supported
# paths--absolute and partial paths.
#
-# Absolute paths are derived from the root device and can follow child<>
+# Absolute paths are derived from the root object and can follow child<>
# or link<> properties. Since they can follow link<> properties, they
# can be arbitrarily long. Absolute paths look like absolute filenames
# and are prefixed with a leading slash.
#
# Partial paths look like relative filenames. They do not begin
# with a prefix. The matching rules for partial paths are subtle but
-# designed to make specifying devices easy. At each level of the
+# designed to make specifying objects easy. At each level of the
# composition tree, the partial path is matched as an absolute path.
# The first match is not returned. At least two matches are searched
# for. A successful result is only returned if only one match is
@@ -1259,7 +1294,7 @@
##
# @qom-set:
#
-# This command will set a property from a device model path.
+# This command will set a property from a object model path.
#
# @path: see @qom-get for a description of this parameter
#
@@ -1275,3 +1310,275 @@
{ 'command': 'qom-set',
'data': { 'path': 'str', 'property': 'str', 'value': 'visitor' },
'gen': 'no' }
+
+##
+# @set_password:
+#
+# Sets the password of a remote display session.
+#
+# @protocol: `vnc' to modify the VNC server password
+# `spice' to modify the Spice server password
+#
+# @password: the new password
+#
+# @connected: #optional how to handle existing clients when changing the
+# password. If nothing is specified, defaults to `keep'
+# `fail' to fail the command if clients are connected
+# `disconnect' to disconnect existing clients
+# `keep' to maintain existing clients
+#
+# Returns: Nothing on success
+# If Spice is not enabled, DeviceNotFound
+# If @protocol does not support connected, InvalidParameter
+# If @protocol is invalid, InvalidParameter
+# If any other error occurs, SetPasswdFailed
+#
+# Notes: If VNC is not enabled, SetPasswdFailed is returned.
+#
+# Since: 0.14.0
+##
+{ 'command': 'set_password',
+ 'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} }
+
+##
+# @expire_password:
+#
+# Expire the password of a remote display server.
+#
+# @protocol: the name of the remote display protocol `vnc' or `spice'
+#
+# @time: when to expire the password.
+# `now' to expire the password immediately
+# `never' to cancel password expiration
+# `+INT' where INT is the number of seconds from now (integer)
+# `INT' where INT is the absolute time in seconds
+#
+# Returns: Nothing on success
+# If @protocol is `spice' and Spice is not active, DeviceNotFound
+# If an error occurs setting password expiration, SetPasswdFailed
+# If @protocol is not `spice' or 'vnc', InvalidParameter
+#
+# Since: 0.14.0
+#
+# Notes: Time is relative to the server and currently there is no way to
+# coordinate server time with client time. It is not recommended to
+# use the absolute time version of the @time parameter unless you're
+# sure you are on the same machine as the QEMU instance.
+##
+{ 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} }
+
+##
+# @eject:
+#
+# Ejects a device from a removable drive.
+#
+# @device: The name of the device
+#
+# @force: @optional If true, eject regardless of whether the drive is locked.
+# If not specified, the default value is false.
+#
+# Returns: Nothing on success
+# If @device is not a valid block device, DeviceNotFound
+# If @device is not removable and @force is false, DeviceNotRemovable
+# If @force is false and @device is locked, DeviceLocked
+#
+# Notes: Ejecting a device will no media results in success
+#
+# Since: 0.14.0
+##
+{ 'command': 'eject', 'data': {'device': 'str', '*force': 'bool'} }
+
+##
+# @change-vnc-password:
+#
+# Change the VNC server password.
+#
+# @target: the new password to use with VNC authentication
+#
+# Since: 1.1
+#
+# Notes: An empty password in this command will set the password to the empty
+# string. Existing clients are unaffected by executing this command.
+##
+{ 'command': 'change-vnc-password', 'data': {'password': 'str'} }
+
+##
+# @change:
+#
+# This command is multiple commands multiplexed together.
+#
+# @device: This is normally the name of a block device but it may also be 'vnc'.
+# when it's 'vnc', then sub command depends on @target
+#
+# @target: If @device is a block device, then this is the new filename.
+# If @device is 'vnc', then if the value 'password' selects the vnc
+# change password command. Otherwise, this specifies a new server URI
+# address to listen to for VNC connections.
+#
+# @arg: If @device is a block device, then this is an optional format to open
+# the device with.
+# If @device is 'vnc' and @target is 'password', this is the new VNC
+# password to set. If this argument is an empty string, then no future
+# logins will be allowed.
+#
+# Returns: Nothing on success.
+# If @device is not a valid block device, DeviceNotFound
+# If @format is not a valid block format, InvalidBlockFormat
+# If the new block device is encrypted, DeviceEncrypted. Note that
+# if this error is returned, the device has been opened successfully
+# and an additional call to @block_passwd is required to set the
+# device's password. The behavior of reads and writes to the block
+# device between when these calls are executed is undefined.
+#
+# Notes: It is strongly recommended that this interface is not used especially
+# for changing block devices.
+#
+# Since: 0.14.0
+##
+{ 'command': 'change',
+ 'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
+
+##
+# @block_set_io_throttle:
+#
+# Change I/O throttle limits for a block drive.
+#
+# @device: The name of the device
+#
+# @bps: total throughput limit in bytes per second
+#
+# @bps_rd: read throughput limit in bytes per second
+#
+# @bps_wr: write throughput limit in bytes per second
+#
+# @iops: total I/O operations per second
+#
+# @ops_rd: read I/O operations per second
+#
+# @iops_wr: write I/O operations per second
+#
+# Returns: Nothing on success
+# If @device is not a valid block device, DeviceNotFound
+# If the argument combination is invalid, InvalidParameterCombination
+#
+# Since: 1.1
+##
+{ 'command': 'block_set_io_throttle',
+ 'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
+ 'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
+
+# @block_stream:
+#
+# Copy data from a backing file into a block device.
+#
+# The block streaming operation is performed in the background until the entire
+# backing file has been copied. This command returns immediately once streaming
+# has started. The status of ongoing block streaming operations can be checked
+# with query-block-jobs. The operation can be stopped before it has completed
+# using the block_job_cancel command.
+#
+# If a base file is specified then sectors are not copied from that base file and
+# its backing chain. When streaming completes the image file will have the base
+# file as its backing file. This can be used to stream a subset of the backing
+# file chain instead of flattening the entire image.
+#
+# On successful completion the image file is updated to drop the backing file
+# and the BLOCK_JOB_COMPLETED event is emitted.
+#
+# @device: the device name
+#
+# @base: #optional the common backing file name
+#
+# Returns: Nothing on success
+# If streaming is already active on this device, DeviceInUse
+# If @device does not exist, DeviceNotFound
+# If image streaming is not supported by this device, NotSupported
+# If @base does not exist, BaseNotFound
+#
+# Since: 1.1
+##
+{ 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
+
+##
+# @block_job_set_speed:
+#
+# Set maximum speed for a background block operation.
+#
+# This command can only be issued when there is an active block job.
+#
+# Throttling can be disabled by setting the speed to 0.
+#
+# @device: the device name
+#
+# @value: the maximum speed, in bytes per second
+#
+# Returns: Nothing on success
+# If the job type does not support throttling, NotSupported
+# If streaming is not active on this device, DeviceNotActive
+#
+# Since: 1.1
+##
+{ 'command': 'block_job_set_speed',
+ 'data': { 'device': 'str', 'value': 'int' } }
+
+##
+# @block_job_cancel:
+#
+# Stop an active block streaming operation.
+#
+# This command returns immediately after marking the active block streaming
+# operation for cancellation. It is an error to call this command if no
+# operation is in progress.
+#
+# The operation will cancel as soon as possible and then emit the
+# BLOCK_JOB_CANCELLED event. Before that happens the job is still visible when
+# enumerated using query-block-jobs.
+#
+# The image file retains its backing file unless the streaming operation happens
+# to complete just as it is being cancelled.
+#
+# A new block streaming operation can be started at a later time to finish
+# copying all data from the backing file.
+#
+# @device: the device name
+#
+# Returns: Nothing on success
+# If streaming is not active on this device, DeviceNotActive
+# If cancellation already in progress, DeviceInUse
+#
+# Since: 1.1
+##
+{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
+
+##
+# @ObjectTypeInfo:
+#
+# This structure describes a search result from @qom-list-types
+#
+# @name: the type name found in the search
+#
+# Since: 1.1
+#
+# Notes: This command is experimental and may change syntax in future releases.
+##
+{ 'type': 'ObjectTypeInfo',
+ 'data': { 'name': 'str' } }
+
+##
+# @qom-list-types:
+#
+# This command will return a list of types given search parameters
+#
+# @implements: if specified, only return types that implement this type name
+#
+# @abstract: if true, include abstract types in the results
+#
+# Returns: a list of @ObjectTypeInfo or an empty list if no results are found
+#
+# Since: 1.1
+#
+# Notes: This command is experimental and may change syntax in future releases.
+##
+{ 'command': 'qom-list-types',
+ 'data': { '*implements': 'str', '*abstract': 'bool' },
+ 'returns': [ 'ObjectTypeInfo' ] }
diff --git a/qemu-bridge-helper.c b/qemu-bridge-helper.c
new file mode 100644
index 0000000000..aec5008e22
--- /dev/null
+++ b/qemu-bridge-helper.c
@@ -0,0 +1,410 @@
+/*
+ * QEMU Bridge Helper
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Richa Marwaha <rmarwah@linux.vnet.ibm.com>
+ * Corey Bryant <coreyb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "config-host.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <glib.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/prctl.h>
+
+#include <net/if.h>
+
+#include <linux/sockios.h>
+
+#include "qemu-queue.h"
+
+#include "net/tap-linux.h"
+
+#ifdef CONFIG_LIBCAP
+#include <cap-ng.h>
+#endif
+
+#define DEFAULT_ACL_FILE CONFIG_QEMU_CONFDIR "/bridge.conf"
+
+enum {
+ ACL_ALLOW = 0,
+ ACL_ALLOW_ALL,
+ ACL_DENY,
+ ACL_DENY_ALL,
+};
+
+typedef struct ACLRule {
+ int type;
+ char iface[IFNAMSIZ];
+ QSIMPLEQ_ENTRY(ACLRule) entry;
+} ACLRule;
+
+typedef QSIMPLEQ_HEAD(ACLList, ACLRule) ACLList;
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: qemu-bridge-helper [--use-vnet] --br=bridge --fd=unixfd\n");
+}
+
+static int parse_acl_file(const char *filename, ACLList *acl_list)
+{
+ FILE *f;
+ char line[4096];
+ ACLRule *acl_rule;
+
+ f = fopen(filename, "r");
+ if (f == NULL) {
+ return -1;
+ }
+
+ while (fgets(line, sizeof(line), f) != NULL) {
+ char *ptr = line;
+ char *cmd, *arg, *argend;
+
+ while (isspace(*ptr)) {
+ ptr++;
+ }
+
+ /* skip comments and empty lines */
+ if (*ptr == '#' || *ptr == 0) {
+ continue;
+ }
+
+ cmd = ptr;
+ arg = strchr(cmd, ' ');
+ if (arg == NULL) {
+ arg = strchr(cmd, '\t');
+ }
+
+ if (arg == NULL) {
+ fprintf(stderr, "Invalid config line:\n %s\n", line);
+ fclose(f);
+ errno = EINVAL;
+ return -1;
+ }
+
+ *arg = 0;
+ arg++;
+ while (isspace(*arg)) {
+ arg++;
+ }
+
+ argend = arg + strlen(arg);
+ while (arg != argend && isspace(*(argend - 1))) {
+ argend--;
+ }
+ *argend = 0;
+
+ if (strcmp(cmd, "deny") == 0) {
+ acl_rule = g_malloc(sizeof(*acl_rule));
+ if (strcmp(arg, "all") == 0) {
+ acl_rule->type = ACL_DENY_ALL;
+ } else {
+ acl_rule->type = ACL_DENY;
+ snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
+ }
+ QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
+ } else if (strcmp(cmd, "allow") == 0) {
+ acl_rule = g_malloc(sizeof(*acl_rule));
+ if (strcmp(arg, "all") == 0) {
+ acl_rule->type = ACL_ALLOW_ALL;
+ } else {
+ acl_rule->type = ACL_ALLOW;
+ snprintf(acl_rule->iface, IFNAMSIZ, "%s", arg);
+ }
+ QSIMPLEQ_INSERT_TAIL(acl_list, acl_rule, entry);
+ } else if (strcmp(cmd, "include") == 0) {
+ /* ignore errors */
+ parse_acl_file(arg, acl_list);
+ } else {
+ fprintf(stderr, "Unknown command `%s'\n", cmd);
+ fclose(f);
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+static bool has_vnet_hdr(int fd)
+{
+ unsigned int features = 0;
+
+ if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
+ return false;
+ }
+
+ if (!(features & IFF_VNET_HDR)) {
+ return false;
+ }
+
+ return true;
+}
+
+static void prep_ifreq(struct ifreq *ifr, const char *ifname)
+{
+ memset(ifr, 0, sizeof(*ifr));
+ snprintf(ifr->ifr_name, IFNAMSIZ, "%s", ifname);
+}
+
+static int send_fd(int c, int fd)
+{
+ char msgbuf[CMSG_SPACE(sizeof(fd))];
+ struct msghdr msg = {
+ .msg_control = msgbuf,
+ .msg_controllen = sizeof(msgbuf),
+ };
+ struct cmsghdr *cmsg;
+ struct iovec iov;
+ char req[1] = { 0x00 };
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ msg.msg_controllen = cmsg->cmsg_len;
+
+ iov.iov_base = req;
+ iov.iov_len = sizeof(req);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+
+ return sendmsg(c, &msg, 0);
+}
+
+#ifdef CONFIG_LIBCAP
+static int drop_privileges(void)
+{
+ /* clear all capabilities */
+ capng_clear(CAPNG_SELECT_BOTH);
+
+ if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
+ CAP_NET_ADMIN) < 0) {
+ return -1;
+ }
+
+ /* change to calling user's real uid and gid, retaining supplemental
+ * groups and CAP_NET_ADMIN */
+ if (capng_change_id(getuid(), getgid(), CAPNG_CLEAR_BOUNDING)) {
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+ struct ifreq ifr;
+ int fd, ctlfd, unixfd = -1;
+ int use_vnet = 0;
+ int mtu;
+ const char *bridge = NULL;
+ char iface[IFNAMSIZ];
+ int index;
+ ACLRule *acl_rule;
+ ACLList acl_list;
+ int access_allowed, access_denied;
+ int ret = EXIT_SUCCESS;
+
+#ifdef CONFIG_LIBCAP
+ /* if we're run from an suid binary, immediately drop privileges preserving
+ * cap_net_admin */
+ if (geteuid() == 0 && getuid() != geteuid()) {
+ if (drop_privileges() == -1) {
+ fprintf(stderr, "failed to drop privileges\n");
+ return 1;
+ }
+ }
+#endif
+
+ /* parse arguments */
+ for (index = 1; index < argc; index++) {
+ if (strcmp(argv[index], "--use-vnet") == 0) {
+ use_vnet = 1;
+ } else if (strncmp(argv[index], "--br=", 5) == 0) {
+ bridge = &argv[index][5];
+ } else if (strncmp(argv[index], "--fd=", 5) == 0) {
+ unixfd = atoi(&argv[index][5]);
+ } else {
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (bridge == NULL || unixfd == -1) {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ /* parse default acl file */
+ QSIMPLEQ_INIT(&acl_list);
+ if (parse_acl_file(DEFAULT_ACL_FILE, &acl_list) == -1) {
+ fprintf(stderr, "failed to parse default acl file `%s'\n",
+ DEFAULT_ACL_FILE);
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* validate bridge against acl -- default policy is to deny
+ * according acl policy if we have a deny and allow both
+ * then deny should always win over allow
+ */
+ access_allowed = 0;
+ access_denied = 0;
+ QSIMPLEQ_FOREACH(acl_rule, &acl_list, entry) {
+ switch (acl_rule->type) {
+ case ACL_ALLOW_ALL:
+ access_allowed = 1;
+ break;
+ case ACL_ALLOW:
+ if (strcmp(bridge, acl_rule->iface) == 0) {
+ access_allowed = 1;
+ }
+ break;
+ case ACL_DENY_ALL:
+ access_denied = 1;
+ break;
+ case ACL_DENY:
+ if (strcmp(bridge, acl_rule->iface) == 0) {
+ access_denied = 1;
+ }
+ break;
+ }
+ }
+
+ if ((access_allowed == 0) || (access_denied == 1)) {
+ fprintf(stderr, "access denied by acl file\n");
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* open a socket to use to control the network interfaces */
+ ctlfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (ctlfd == -1) {
+ fprintf(stderr, "failed to open control socket: %s\n", strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* open the tap device */
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd == -1) {
+ fprintf(stderr, "failed to open /dev/net/tun: %s\n", strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* request a tap device, disable PI, and add vnet header support if
+ * requested and it's available. */
+ prep_ifreq(&ifr, "tap%d");
+ ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+ if (use_vnet && has_vnet_hdr(fd)) {
+ ifr.ifr_flags |= IFF_VNET_HDR;
+ }
+
+ if (ioctl(fd, TUNSETIFF, &ifr) == -1) {
+ fprintf(stderr, "failed to create tun device: %s\n", strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* save tap device name */
+ snprintf(iface, sizeof(iface), "%s", ifr.ifr_name);
+
+ /* get the mtu of the bridge */
+ prep_ifreq(&ifr, bridge);
+ if (ioctl(ctlfd, SIOCGIFMTU, &ifr) == -1) {
+ fprintf(stderr, "failed to get mtu of bridge `%s': %s\n",
+ bridge, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* save mtu */
+ mtu = ifr.ifr_mtu;
+
+ /* set the mtu of the interface based on the bridge */
+ prep_ifreq(&ifr, iface);
+ ifr.ifr_mtu = mtu;
+ if (ioctl(ctlfd, SIOCSIFMTU, &ifr) == -1) {
+ fprintf(stderr, "failed to set mtu of device `%s' to %d: %s\n",
+ iface, mtu, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* add the interface to the bridge */
+ prep_ifreq(&ifr, bridge);
+ ifr.ifr_ifindex = if_nametoindex(iface);
+
+ if (ioctl(ctlfd, SIOCBRADDIF, &ifr) == -1) {
+ fprintf(stderr, "failed to add interface `%s' to bridge `%s': %s\n",
+ iface, bridge, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* bring the interface up */
+ prep_ifreq(&ifr, iface);
+ if (ioctl(ctlfd, SIOCGIFFLAGS, &ifr) == -1) {
+ fprintf(stderr, "failed to get interface flags for `%s': %s\n",
+ iface, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(ctlfd, SIOCSIFFLAGS, &ifr) == -1) {
+ fprintf(stderr, "failed to bring up interface `%s': %s\n",
+ iface, strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* write fd to the domain socket */
+ if (send_fd(unixfd, fd) == -1) {
+ fprintf(stderr, "failed to write fd to unix socket: %s\n",
+ strerror(errno));
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ /* ... */
+
+ /* profit! */
+
+cleanup:
+
+ while ((acl_rule = QSIMPLEQ_FIRST(&acl_list)) != NULL) {
+ QSIMPLEQ_REMOVE_HEAD(&acl_list, entry);
+ g_free(acl_rule);
+ }
+
+ return ret;
+}
diff --git a/qemu-char.c b/qemu-char.c
index 27abcb9186..b1d80dd24e 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2903,3 +2903,13 @@ CharDriverState *qemu_chr_find(const char *name)
}
return NULL;
}
+
+/* Get a character (serial) device interface. */
+CharDriverState *qemu_char_get_next_serial(void)
+{
+ static int next_serial;
+
+ /* FIXME: This function needs to go away: use chardev properties! */
+ return serial_hds[next_serial++];
+}
+
diff --git a/qemu-char.h b/qemu-char.h
index 8ca1e2d54e..486644b3bd 100644
--- a/qemu-char.h
+++ b/qemu-char.h
@@ -248,4 +248,6 @@ void qemu_chr_close_mem(CharDriverState *chr);
QString *qemu_chr_mem_to_qs(CharDriverState *chr);
size_t qemu_chr_mem_osize(const CharDriverState *chr);
+CharDriverState *qemu_char_get_next_serial(void);
+
#endif
diff --git a/qemu-common.h b/qemu-common.h
index 6ab7dfb1b9..8b69a9eea5 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -250,6 +250,13 @@ typedef struct QEMUSGList QEMUSGList;
typedef uint64_t pcibus_t;
+typedef enum LostTickPolicy {
+ LOST_TICK_DISCARD,
+ LOST_TICK_DELAY,
+ LOST_TICK_MERGE,
+ LOST_TICK_SLEW,
+} LostTickPolicy;
+
void tcg_exec_init(unsigned long tb_size);
bool tcg_enabled(void);
diff --git a/qemu-config.c b/qemu-config.c
index ecc88e8d40..b030205e23 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -531,6 +531,10 @@ static QemuOptsList qemu_machine_opts = {
.name = "accel",
.type = QEMU_OPT_STRING,
.help = "accelerator list",
+ }, {
+ .name = "kernel_irqchip",
+ .type = QEMU_OPT_BOOL,
+ .help = "use KVM in-kernel irqchip",
},
{ /* End of list */ }
},
diff --git a/qemu-coroutine-sleep.c b/qemu-coroutine-sleep.c
new file mode 100644
index 0000000000..fd65274446
--- /dev/null
+++ b/qemu-coroutine-sleep.c
@@ -0,0 +1,38 @@
+/*
+ * QEMU coroutine sleep
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include "qemu-coroutine.h"
+#include "qemu-timer.h"
+
+typedef struct CoSleepCB {
+ QEMUTimer *ts;
+ Coroutine *co;
+} CoSleepCB;
+
+static void co_sleep_cb(void *opaque)
+{
+ CoSleepCB *sleep_cb = opaque;
+
+ qemu_free_timer(sleep_cb->ts);
+ qemu_coroutine_enter(sleep_cb->co, NULL);
+}
+
+void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns)
+{
+ CoSleepCB sleep_cb = {
+ .co = qemu_coroutine_self(),
+ };
+ sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
+ qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
+ qemu_coroutine_yield();
+}
diff --git a/qemu-coroutine.h b/qemu-coroutine.h
index 8a55fe125e..34c15d4116 100644
--- a/qemu-coroutine.h
+++ b/qemu-coroutine.h
@@ -17,6 +17,7 @@
#include <stdbool.h>
#include "qemu-queue.h"
+#include "qemu-timer.h"
/**
* Coroutines are a mechanism for stack switching and can be used for
@@ -199,4 +200,12 @@ void qemu_co_rwlock_wrlock(CoRwlock *lock);
*/
void qemu_co_rwlock_unlock(CoRwlock *lock);
+/**
+ * Yield the coroutine for a given duration
+ *
+ * Note this function uses timers and hence only works when a main loop is in
+ * use. See main-loop.h and do not use from qemu-tool programs.
+ */
+void coroutine_fn co_sleep_ns(QEMUClock *clock, int64_t ns);
+
#endif /* QEMU_COROUTINE_H */
diff --git a/qemu-io.c b/qemu-io.c
index ffa62fb46f..d4a5fcbcbc 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -130,7 +130,7 @@ static void print_report(const char *op, struct timeval *t, int64_t offset,
static void *
create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
{
- size_t *sizes = calloc(nr_iov, sizeof(size_t));
+ size_t *sizes = g_new0(size_t, nr_iov);
size_t count = 0;
void *buf = NULL;
void *p;
@@ -172,7 +172,7 @@ create_iovec(QEMUIOVector *qiov, char **argv, int nr_iov, int pattern)
}
fail:
- free(sizes);
+ g_free(sizes);
return buf;
}
@@ -471,14 +471,14 @@ static int read_f(int argc, char **argv)
}
if (Pflag) {
- void *cmp_buf = malloc(pattern_count);
+ void *cmp_buf = g_malloc(pattern_count);
memset(cmp_buf, pattern, pattern_count);
if (memcmp(buf + pattern_offset, cmp_buf, pattern_count)) {
printf("Pattern verification failed at offset %"
PRId64 ", %d bytes\n",
offset + pattern_offset, pattern_count);
}
- free(cmp_buf);
+ g_free(cmp_buf);
}
if (qflag) {
@@ -601,13 +601,13 @@ static int readv_f(int argc, char **argv)
}
if (Pflag) {
- void *cmp_buf = malloc(qiov.size);
+ void *cmp_buf = g_malloc(qiov.size);
memset(cmp_buf, pattern, qiov.size);
if (memcmp(buf, cmp_buf, qiov.size)) {
printf("Pattern verification failed at offset %"
PRId64 ", %zd bytes\n", offset, qiov.size);
}
- free(cmp_buf);
+ g_free(cmp_buf);
}
if (qflag) {
@@ -1063,7 +1063,7 @@ static void aio_write_done(void *opaque, int ret)
ctx->qiov.size, 1, ctx->Cflag);
out:
qemu_io_free(ctx->buf);
- free(ctx);
+ g_free(ctx);
}
static void aio_read_done(void *opaque, int ret)
@@ -1079,14 +1079,14 @@ static void aio_read_done(void *opaque, int ret)
}
if (ctx->Pflag) {
- void *cmp_buf = malloc(ctx->qiov.size);
+ void *cmp_buf = g_malloc(ctx->qiov.size);
memset(cmp_buf, ctx->pattern, ctx->qiov.size);
if (memcmp(ctx->buf, cmp_buf, ctx->qiov.size)) {
printf("Pattern verification failed at offset %"
PRId64 ", %zd bytes\n", ctx->offset, ctx->qiov.size);
}
- free(cmp_buf);
+ g_free(cmp_buf);
}
if (ctx->qflag) {
@@ -1103,7 +1103,7 @@ static void aio_read_done(void *opaque, int ret)
ctx->qiov.size, 1, ctx->Cflag);
out:
qemu_io_free(ctx->buf);
- free(ctx);
+ g_free(ctx);
}
static void aio_read_help(void)
@@ -1118,7 +1118,7 @@ static void aio_read_help(void)
" Reads a segment of the currently open file, optionally dumping it to the\n"
" standard output stream (with -v option) for subsequent inspection.\n"
" The read is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed\n"
+" used to ensure all outstanding aio requests have been completed.\n"
" -C, -- report statistics in a machine parsable format\n"
" -P, -- use a pattern to verify read data\n"
" -v, -- dump buffer to standard output\n"
@@ -1141,7 +1141,7 @@ static const cmdinfo_t aio_read_cmd = {
static int aio_read_f(int argc, char **argv)
{
int nr_iov, c;
- struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
while ((c = getopt(argc, argv, "CP:qv")) != EOF) {
switch (c) {
@@ -1152,7 +1152,7 @@ static int aio_read_f(int argc, char **argv)
ctx->Pflag = 1;
ctx->pattern = parse_pattern(optarg);
if (ctx->pattern < 0) {
- free(ctx);
+ g_free(ctx);
return 0;
}
break;
@@ -1163,20 +1163,20 @@ static int aio_read_f(int argc, char **argv)
ctx->vflag = 1;
break;
default:
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_read_cmd);
}
}
if (optind > argc - 2) {
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_read_cmd);
}
ctx->offset = cvtnum(argv[optind]);
if (ctx->offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
- free(ctx);
+ g_free(ctx);
return 0;
}
optind++;
@@ -1184,14 +1184,14 @@ static int aio_read_f(int argc, char **argv)
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
- free(ctx);
+ g_free(ctx);
return 0;
}
nr_iov = argc - optind;
ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, 0xab);
if (ctx->buf == NULL) {
- free(ctx);
+ g_free(ctx);
return 0;
}
@@ -1214,7 +1214,7 @@ static void aio_write_help(void)
" Writes into a segment of the currently open file, using a buffer\n"
" filled with a set pattern (0xcdcdcdcd).\n"
" The write is performed asynchronously and the aio_flush command must be\n"
-" used to ensure all outstanding aio requests have been completed\n"
+" used to ensure all outstanding aio requests have been completed.\n"
" -P, -- use different pattern to fill file\n"
" -C, -- report statistics in a machine parsable format\n"
" -q, -- quiet mode, do not show I/O statistics\n"
@@ -1237,7 +1237,7 @@ static int aio_write_f(int argc, char **argv)
{
int nr_iov, c;
int pattern = 0xcd;
- struct aio_ctx *ctx = calloc(1, sizeof(struct aio_ctx));
+ struct aio_ctx *ctx = g_new0(struct aio_ctx, 1);
while ((c = getopt(argc, argv, "CqP:")) != EOF) {
switch (c) {
@@ -1250,25 +1250,25 @@ static int aio_write_f(int argc, char **argv)
case 'P':
pattern = parse_pattern(optarg);
if (pattern < 0) {
- free(ctx);
+ g_free(ctx);
return 0;
}
break;
default:
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_write_cmd);
}
}
if (optind > argc - 2) {
- free(ctx);
+ g_free(ctx);
return command_usage(&aio_write_cmd);
}
ctx->offset = cvtnum(argv[optind]);
if (ctx->offset < 0) {
printf("non-numeric length argument -- %s\n", argv[optind]);
- free(ctx);
+ g_free(ctx);
return 0;
}
optind++;
@@ -1276,14 +1276,14 @@ static int aio_write_f(int argc, char **argv)
if (ctx->offset & 0x1ff) {
printf("offset %" PRId64 " is not sector aligned\n",
ctx->offset);
- free(ctx);
+ g_free(ctx);
return 0;
}
nr_iov = argc - optind;
ctx->buf = create_iovec(&ctx->qiov, &argv[optind], nr_iov, pattern);
if (ctx->buf == NULL) {
- free(ctx);
+ g_free(ctx);
return 0;
}
diff --git a/qemu-option.c b/qemu-option.c
index a303f87e1c..4626ccfe54 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -603,7 +603,8 @@ static void qemu_opt_del(QemuOpt *opt)
g_free(opt);
}
-int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+static int opt_set(QemuOpts *opts, const char *name, const char *value,
+ bool prepend)
{
QemuOpt *opt;
const QemuOptDesc *desc = opts->list->desc;
@@ -626,7 +627,11 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
opt = g_malloc0(sizeof(*opt));
opt->name = g_strdup(name);
opt->opts = opts;
- QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+ if (prepend) {
+ QTAILQ_INSERT_HEAD(&opts->head, opt, next);
+ } else {
+ QTAILQ_INSERT_TAIL(&opts->head, opt, next);
+ }
if (desc[i].name != NULL) {
opt->desc = desc+i;
}
@@ -640,6 +645,11 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
return 0;
}
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+{
+ return opt_set(opts, name, value, false);
+}
+
int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
{
QemuOpt *opt;
@@ -691,6 +701,9 @@ QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
QTAILQ_FOREACH(opts, &list->head, next) {
if (!opts->id) {
+ if (!id) {
+ return opts;
+ }
continue;
}
if (strcmp(opts->id, id) != 0) {
@@ -806,7 +819,8 @@ int qemu_opts_print(QemuOpts *opts, void *dummy)
return 0;
}
-int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+static int opts_do_parse(QemuOpts *opts, const char *params,
+ const char *firstname, bool prepend)
{
char option[128], value[1024];
const char *p,*pe,*pc;
@@ -841,7 +855,7 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname
}
if (strcmp(option, "id") != 0) {
/* store and parse */
- if (qemu_opt_set(opts, option, value) == -1) {
+ if (opt_set(opts, option, value, prepend) == -1) {
return -1;
}
}
@@ -852,8 +866,13 @@ int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname
return 0;
}
-QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
- int permit_abbrev)
+int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
+{
+ return opts_do_parse(opts, params, firstname, false);
+}
+
+static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
+ int permit_abbrev, bool defaults)
{
const char *firstname;
char value[1024], *id = NULL;
@@ -870,11 +889,19 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
get_opt_value(value, sizeof(value), p+4);
id = value;
}
- opts = qemu_opts_create(list, id, 1);
+ if (defaults) {
+ if (!id && !QTAILQ_EMPTY(&list->head)) {
+ opts = qemu_opts_find(list, NULL);
+ } else {
+ opts = qemu_opts_create(list, id, 0);
+ }
+ } else {
+ opts = qemu_opts_create(list, id, 1);
+ }
if (opts == NULL)
return NULL;
- if (qemu_opts_do_parse(opts, params, firstname) != 0) {
+ if (opts_do_parse(opts, params, firstname, defaults) != 0) {
qemu_opts_del(opts);
return NULL;
}
@@ -882,6 +909,21 @@ QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
return opts;
}
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
+ int permit_abbrev)
+{
+ return opts_parse(list, params, permit_abbrev, false);
+}
+
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+ int permit_abbrev)
+{
+ QemuOpts *opts;
+
+ opts = opts_parse(list, params, permit_abbrev, true);
+ assert(opts);
+}
+
static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
{
char buf[32];
diff --git a/qemu-option.h b/qemu-option.h
index 07958e4e90..e6f61e6e35 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -125,6 +125,8 @@ void qemu_opts_del(QemuOpts *opts);
int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc);
int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname);
QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int permit_abbrev);
+void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
+ int permit_abbrev);
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict);
QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
diff --git a/qemu-options.hx b/qemu-options.hx
index 0cefd1852f..f577cc8470 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -31,7 +31,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
"-machine [type=]name[,prop[=value][,...]]\n"
" selects emulated machine (-machine ? for list)\n"
" property accel=accel1[:accel2[:...]] selects accelerator\n"
- " supported accelerators are kvm, xen, tcg (default: tcg)\n",
+ " supported accelerators are kvm, xen, tcg (default: tcg)\n"
+ " kernel_irqchip=on|off controls accelerated irqchip support\n",
QEMU_ARCH_ALL)
STEXI
@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -44,6 +45,8 @@ This is used to enable an accelerator. Depending on the target architecture,
kvm, xen, or tcg can be available. By default, tcg is used. If there is more
than one accelerator specified, the next one is used if the previous one fails
to initialize.
+@item kernel_irqchip=on|off
+Enables in-kernel irqchip support for the chosen accelerator when available.
@end table
ETEXI
@@ -1221,11 +1224,14 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
"-net tap[,vlan=n][,name=str],ifname=name\n"
" connect the host TAP network interface to VLAN 'n'\n"
#else
- "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
- " connect the host TAP network interface to VLAN 'n' and use the\n"
- " network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
- " and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
+ "-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile][,helper=helper][,sndbuf=nbytes][,vnet_hdr=on|off][,vhost=on|off][,vhostfd=h][,vhostforce=on|off]\n"
+ " connect the host TAP network interface to VLAN 'n' \n"
+ " use network scripts 'file' (default=" DEFAULT_NETWORK_SCRIPT ")\n"
+ " to configure it and 'dfile' (default=" DEFAULT_NETWORK_DOWN_SCRIPT ")\n"
+ " to deconfigure it\n"
" use '[down]script=no' to disable script execution\n"
+ " use network helper 'helper' (default=" DEFAULT_BRIDGE_HELPER ") to\n"
+ " configure it\n"
" use 'fd=h' to connect to an already opened TAP interface\n"
" use 'sndbuf=nbytes' to limit the size of the send buffer (the\n"
" default is disabled 'sndbuf=0' to enable flow control set 'sndbuf=1048576')\n"
@@ -1235,6 +1241,10 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
" (only has effect for virtio guests which use MSIX)\n"
" use vhostforce=on to force vhost on for non-MSIX virtio guests\n"
" use 'vhostfd=h' to connect to an already opened vhost net device\n"
+ "-net bridge[,vlan=n][,name=str][,br=bridge][,helper=helper]\n"
+ " connects a host TAP network interface to a host bridge device 'br'\n"
+ " (default=" DEFAULT_BRIDGE_INTERFACE ") using the program 'helper'\n"
+ " (default=" DEFAULT_BRIDGE_HELPER ")\n"
#endif
"-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
" connect the vlan 'n' to another VLAN using a socket connection\n"
@@ -1260,6 +1270,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev,
"user|"
#endif
"tap|"
+ "bridge|"
#ifdef CONFIG_VDE
"vde|"
#endif
@@ -1396,26 +1407,65 @@ processed and applied to -net user. Mixing them with the new configuration
syntax gives undefined results. Their use for new applications is discouraged
as they will be removed from future versions.
-@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}] [,script=@var{file}][,downscript=@var{dfile}]
-Connect the host TAP network interface @var{name} to VLAN @var{n}, use
-the network script @var{file} to configure it and the network script
+@item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}]
+Connect the host TAP network interface @var{name} to VLAN @var{n}.
+
+Use the network script @var{file} to configure it and the network script
@var{dfile} to deconfigure it. If @var{name} is not provided, the OS
-automatically provides one. @option{fd}=@var{h} can be used to specify
-the handle of an already opened host TAP interface. The default network
-configure script is @file{/etc/qemu-ifup} and the default network
-deconfigure script is @file{/etc/qemu-ifdown}. Use @option{script=no}
-or @option{downscript=no} to disable script execution. Example:
+automatically provides one. The default network configure script is
+@file{/etc/qemu-ifup} and the default network deconfigure script is
+@file{/etc/qemu-ifdown}. Use @option{script=no} or @option{downscript=no}
+to disable script execution.
+
+If running QEMU as an unprivileged user, use the network helper
+@var{helper} to configure the TAP interface. The default network
+helper executable is @file{/usr/local/libexec/qemu-bridge-helper}.
+
+@option{fd}=@var{h} can be used to specify the handle of an already
+opened host TAP interface.
+
+Examples:
@example
+#launch a QEMU instance with the default network script
qemu linux.img -net nic -net tap
@end example
-More complicated example (two NICs, each one connected to a TAP device)
@example
+#launch a QEMU instance with two NICs, each one connected
+#to a TAP device
qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
-net nic,vlan=1 -net tap,vlan=1,ifname=tap1
@end example
+@example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge br0
+qemu linux.img -net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
+@end example
+
+@item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}]
+Connect a host TAP network interface to a host bridge device.
+
+Use the network helper @var{helper} to configure the TAP interface and
+attach it to the bridge. The default network helper executable is
+@file{/usr/local/libexec/qemu-bridge-helper} and the default bridge
+device is @file{br0}.
+
+Examples:
+
+@example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge br0
+qemu linux.img -net bridge -net nic,model=virtio
+@end example
+
+@example
+#launch a QEMU instance with the default network helper to
+#connect a TAP device to bridge qemubr0
+qemu linux.img -net bridge,br=qemubr0 -net nic,model=virtio
+@end example
+
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual
diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
index fe9b931863..3524c8b785 100644
--- a/qemu-thread-win32.c
+++ b/qemu-thread-win32.c
@@ -215,8 +215,6 @@ static unsigned __stdcall win32_start_routine(void *arg)
if (data->mode == QEMU_THREAD_DETACHED) {
g_free(data);
data = NULL;
- } else {
- InitializeCriticalSection(&data->cs);
}
TlsSetValue(qemu_thread_tls_index, data);
qemu_thread_exit(start_routine(thread_arg));
@@ -227,6 +225,7 @@ void qemu_thread_exit(void *arg)
{
QemuThreadData *data = TlsGetValue(qemu_thread_tls_index);
if (data) {
+ assert(data->mode != QEMU_THREAD_DETACHED);
data->ret = arg;
EnterCriticalSection(&data->cs);
data->exited = true;
@@ -258,6 +257,7 @@ void *qemu_thread_join(QemuThread *thread)
CloseHandle(handle);
}
ret = data->ret;
+ assert(data->mode != QEMU_THREAD_DETACHED);
DeleteCriticalSection(&data->cs);
g_free(data);
return ret;
@@ -288,6 +288,10 @@ void qemu_thread_create(QemuThread *thread,
data->mode = mode;
data->exited = false;
+ if (data->mode != QEMU_THREAD_DETACHED) {
+ InitializeCriticalSection(&data->cs);
+ }
+
hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
data, 0, &thread->tid);
if (!hThread) {
@@ -314,6 +318,7 @@ HANDLE qemu_thread_get_handle(QemuThread *thread)
return NULL;
}
+ assert(data->mode != QEMU_THREAD_DETACHED);
EnterCriticalSection(&data->cs);
if (!data->exited) {
handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
diff --git a/qemu-timer.c b/qemu-timer.c
index cd026c6495..a22f27e9f8 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -494,35 +494,6 @@ static void host_alarm_handler(int host_signum)
if (!t)
return;
-#if 0
-#define DISP_FREQ 1000
- {
- static int64_t delta_min = INT64_MAX;
- static int64_t delta_max, delta_cum, last_clock, delta, ti;
- static int count;
- ti = qemu_get_clock_ns(vm_clock);
- if (last_clock != 0) {
- delta = ti - last_clock;
- if (delta < delta_min)
- delta_min = delta;
- if (delta > delta_max)
- delta_max = delta;
- delta_cum += delta;
- if (++count == DISP_FREQ) {
- printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
- muldiv64(delta_min, 1000000, get_ticks_per_sec()),
- muldiv64(delta_max, 1000000, get_ticks_per_sec()),
- muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()),
- (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ));
- count = 0;
- delta_min = INT64_MAX;
- delta_max = 0;
- delta_cum = 0;
- }
- }
- last_clock = ti;
- }
-#endif
if (alarm_has_dynticks(t) ||
qemu_next_alarm_deadline () <= 0) {
t->expired = alarm_has_dynticks(t);
diff --git a/qemu-tool.c b/qemu-tool.c
index c73bf7152e..183a583fec 100644
--- a/qemu-tool.c
+++ b/qemu-tool.c
@@ -59,12 +59,12 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
{
}
-int64 cpu_get_clock(void)
+int64_t cpu_get_clock(void)
{
abort();
}
-int64 cpu_get_icount(void)
+int64_t cpu_get_icount(void)
{
abort();
}
@@ -83,11 +83,12 @@ void qemu_clock_warp(QEMUClock *clock)
{
}
-static void __attribute__((constructor)) init_main_loop(void)
+int qemu_init_main_loop(void)
{
init_clocks();
init_timer_alarm();
qemu_clock_enable(vm_clock, false);
+ return main_loop_init();
}
void slirp_select_fill(int *pnfds, fd_set *readfds,
diff --git a/qerror.c b/qerror.c
index 9a75d06301..3d179c87ea 100644
--- a/qerror.c
+++ b/qerror.c
@@ -40,39 +40,54 @@ static const QType qerror_type = {
* "running out of foo: %(foo)%%"
*
* Please keep the entries in alphabetical order.
- * Use "sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c | sort -c"
- * to check.
+ * Use scripts/check-qerror.sh to check.
*/
static const QErrorStringTable qerror_table[] = {
{
+ .error_fmt = QERR_ADD_CLIENT_FAILED,
+ .desc = "Could not add client",
+ },
+ {
.error_fmt = QERR_BAD_BUS_FOR_DEVICE,
.desc = "Device '%(device)' can't go on a %(bad_bus_type) bus",
},
{
- .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
- .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
+ .error_fmt = QERR_BASE_NOT_FOUND,
+ .desc = "Base '%(base)' not found",
},
{
- .error_fmt = QERR_BUS_NOT_FOUND,
- .desc = "Bus '%(bus)' not found",
+ .error_fmt = QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
+ .desc = "Block format '%(format)' used by device '%(name)' does not support feature '%(feature)'",
},
{
.error_fmt = QERR_BUS_NO_HOTPLUG,
.desc = "Bus '%(bus)' does not support hotplugging",
},
{
- .error_fmt = QERR_COMMAND_NOT_FOUND,
- .desc = "The command %(name) has not been found",
+ .error_fmt = QERR_BUS_NOT_FOUND,
+ .desc = "Bus '%(bus)' not found",
},
{
.error_fmt = QERR_COMMAND_DISABLED,
.desc = "The command %(name) has been disabled for this instance",
},
{
+ .error_fmt = QERR_COMMAND_NOT_FOUND,
+ .desc = "The command %(name) has not been found",
+ },
+ {
.error_fmt = QERR_DEVICE_ENCRYPTED,
.desc = "Device '%(device)' is encrypted",
},
{
+ .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
+ .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+ },
+ {
+ .error_fmt = QERR_DEVICE_HAS_NO_MEDIUM,
+ .desc = "Device '%(device)' has no medium",
+ },
+ {
.error_fmt = QERR_DEVICE_INIT_FAILED,
.desc = "Device '%(device)' could not be initialized",
},
@@ -81,8 +96,8 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' is in use",
},
{
- .error_fmt = QERR_DEVICE_FEATURE_BLOCKS_MIGRATION,
- .desc = "Migration is disabled when using feature '%(feature)' in device '%(device)'",
+ .error_fmt = QERR_DEVICE_IS_READ_ONLY,
+ .desc = "Device '%(device)' is read only",
},
{
.error_fmt = QERR_DEVICE_LOCKED,
@@ -93,6 +108,14 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' has multiple child busses",
},
{
+ .error_fmt = QERR_DEVICE_NO_BUS,
+ .desc = "Device '%(device)' has no child bus",
+ },
+ {
+ .error_fmt = QERR_DEVICE_NO_HOTPLUG,
+ .desc = "Device '%(device)' does not support hotplugging",
+ },
+ {
.error_fmt = QERR_DEVICE_NOT_ACTIVE,
.desc = "Device '%(device)' has not been activated",
},
@@ -109,14 +132,6 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Device '%(device)' is not removable",
},
{
- .error_fmt = QERR_DEVICE_NO_BUS,
- .desc = "Device '%(device)' has no child bus",
- },
- {
- .error_fmt = QERR_DEVICE_NO_HOTPLUG,
- .desc = "Device '%(device)' does not support hotplugging",
- },
- {
.error_fmt = QERR_DUPLICATE_ID,
.desc = "Duplicate ID '%(id)' for %(object)",
},
@@ -141,8 +156,12 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Invalid parameter '%(name)'",
},
{
+ .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
+ .desc = "Invalid parameter combination",
+ },
+ {
.error_fmt = QERR_INVALID_PARAMETER_TYPE,
- .desc = "Invalid parameter type, expected: %(expected)",
+ .desc = "Invalid parameter type for '%(name)', expected: %(expected)",
},
{
.error_fmt = QERR_INVALID_PARAMETER_VALUE,
@@ -157,15 +176,15 @@ static const QErrorStringTable qerror_table[] = {
.desc = "An IO error has occurred",
},
{
- .error_fmt = QERR_JSON_PARSING,
- .desc = "Invalid JSON syntax",
- },
- {
.error_fmt = QERR_JSON_PARSE_ERROR,
.desc = "JSON parse error, %(message)",
},
{
+ .error_fmt = QERR_JSON_PARSING,
+ .desc = "Invalid JSON syntax",
+ },
+ {
.error_fmt = QERR_KVM_MISSING_CAP,
.desc = "Using KVM without %(capability), %(feature) unavailable",
},
@@ -182,6 +201,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "No '%(bus)' bus found for device '%(device)'",
},
{
+ .error_fmt = QERR_NOT_SUPPORTED,
+ .desc = "Not supported",
+ },
+ {
.error_fmt = QERR_OPEN_FILE_FAILED,
.desc = "Could not open '%(filename)'",
},
@@ -211,6 +234,14 @@ static const QErrorStringTable qerror_table[] = {
"value %(value) (minimum: %(min), maximum: %(max)'",
},
{
+ .error_fmt = QERR_QGA_COMMAND_FAILED,
+ .desc = "Guest agent command failed, error was '%(message)'",
+ },
+ {
+ .error_fmt = QERR_QGA_LOGGING_FAILED,
+ .desc = "Guest agent failed to log non-optional log statement",
+ },
+ {
.error_fmt = QERR_QMP_BAD_INPUT_OBJECT,
.desc = "Expected '%(expected)' in QMP input",
},
@@ -231,10 +262,6 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Could not set password",
},
{
- .error_fmt = QERR_ADD_CLIENT_FAILED,
- .desc = "Could not add client",
- },
- {
.error_fmt = QERR_TOO_MANY_FILES,
.desc = "Too many open files",
},
@@ -243,15 +270,15 @@ static const QErrorStringTable qerror_table[] = {
.desc = "An undefined error has occurred",
},
{
- .error_fmt = QERR_UNSUPPORTED,
- .desc = "this feature or command is not currently supported",
- },
- {
.error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
.desc = "'%(device)' uses a %(format) feature which is not "
"supported by this qemu version: %(feature)",
},
{
+ .error_fmt = QERR_UNSUPPORTED,
+ .desc = "this feature or command is not currently supported",
+ },
+ {
.error_fmt = QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
.desc = "Migration is disabled when VirtFS export path '%(path)' "
"is mounted in the guest using mount_tag '%(tag)'",
@@ -260,18 +287,6 @@ static const QErrorStringTable qerror_table[] = {
.error_fmt = QERR_VNC_SERVER_FAILED,
.desc = "Could not start VNC server on %(target)",
},
- {
- .error_fmt = QERR_QGA_LOGGING_FAILED,
- .desc = "Guest agent failed to log non-optional log statement",
- },
- {
- .error_fmt = QERR_QGA_COMMAND_FAILED,
- .desc = "Guest agent command failed, error was '%(message)'",
- },
- {
- .error_fmt = QERR_INVALID_PARAMETER_COMBINATION,
- .desc = "Invalid parameter combination",
- },
{}
};
diff --git a/qerror.h b/qerror.h
index efda232db3..8c36ddb7e1 100644
--- a/qerror.h
+++ b/qerror.h
@@ -49,28 +49,43 @@ QError *qobject_to_qerror(const QObject *obj);
/*
* QError class list
* Please keep the definitions in alphabetical order.
- * Use "grep '^#define QERR_' qerror.h | sort -c" to check.
+ * Use scripts/check-qerror.sh to check.
*/
+#define QERR_ADD_CLIENT_FAILED \
+ "{ 'class': 'AddClientFailed', 'data': {} }"
+
#define QERR_BAD_BUS_FOR_DEVICE \
"{ 'class': 'BadBusForDevice', 'data': { 'device': %s, 'bad_bus_type': %s } }"
+#define QERR_BASE_NOT_FOUND \
+ "{ 'class': 'BaseNotFound', 'data': { 'base': %s } }"
+
#define QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED \
"{ 'class': 'BlockFormatFeatureNotSupported', 'data': { 'format': %s, 'name': %s, 'feature': %s } }"
-#define QERR_BUS_NOT_FOUND \
- "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
+#define QERR_BUFFER_OVERRUN \
+ "{ 'class': 'BufferOverrun', 'data': {} }"
#define QERR_BUS_NO_HOTPLUG \
"{ 'class': 'BusNoHotplug', 'data': { 'bus': %s } }"
-#define QERR_COMMAND_NOT_FOUND \
- "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+#define QERR_BUS_NOT_FOUND \
+ "{ 'class': 'BusNotFound', 'data': { 'bus': %s } }"
#define QERR_COMMAND_DISABLED \
"{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+#define QERR_COMMAND_NOT_FOUND \
+ "{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+
#define QERR_DEVICE_ENCRYPTED \
- "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }"
+ "{ 'class': 'DeviceEncrypted', 'data': { 'device': %s, 'filename': %s } }"
+
+#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
+ "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+
+#define QERR_DEVICE_HAS_NO_MEDIUM \
+ "{ 'class': 'DeviceHasNoMedium', 'data': { 'device': %s } }"
#define QERR_DEVICE_INIT_FAILED \
"{ 'class': 'DeviceInitFailed', 'data': { 'device': %s } }"
@@ -78,8 +93,8 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_IN_USE \
"{ 'class': 'DeviceInUse', 'data': { 'device': %s } }"
-#define QERR_DEVICE_FEATURE_BLOCKS_MIGRATION \
- "{ 'class': 'DeviceFeatureBlocksMigration', 'data': { 'device': %s, 'feature': %s } }"
+#define QERR_DEVICE_IS_READ_ONLY \
+ "{ 'class': 'DeviceIsReadOnly', 'data': { 'device': %s } }"
#define QERR_DEVICE_LOCKED \
"{ 'class': 'DeviceLocked', 'data': { 'device': %s } }"
@@ -87,6 +102,12 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_MULTIPLE_BUSSES \
"{ 'class': 'DeviceMultipleBusses', 'data': { 'device': %s } }"
+#define QERR_DEVICE_NO_BUS \
+ "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
+
+#define QERR_DEVICE_NO_HOTPLUG \
+ "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
+
#define QERR_DEVICE_NOT_ACTIVE \
"{ 'class': 'DeviceNotActive', 'data': { 'device': %s } }"
@@ -99,12 +120,6 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_DEVICE_NOT_REMOVABLE \
"{ 'class': 'DeviceNotRemovable', 'data': { 'device': %s } }"
-#define QERR_DEVICE_NO_BUS \
- "{ 'class': 'DeviceNoBus', 'data': { 'device': %s } }"
-
-#define QERR_DEVICE_NO_HOTPLUG \
- "{ 'class': 'DeviceNoHotplug', 'data': { 'device': %s } }"
-
#define QERR_DUPLICATE_ID \
"{ 'class': 'DuplicateId', 'data': { 'id': %s, 'object': %s } }"
@@ -114,12 +129,18 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_FD_NOT_SUPPLIED \
"{ 'class': 'FdNotSupplied', 'data': {} }"
+#define QERR_FEATURE_DISABLED \
+ "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
+
#define QERR_INVALID_BLOCK_FORMAT \
"{ 'class': 'InvalidBlockFormat', 'data': { 'name': %s } }"
#define QERR_INVALID_PARAMETER \
"{ 'class': 'InvalidParameter', 'data': { 'name': %s } }"
+#define QERR_INVALID_PARAMETER_COMBINATION \
+ "{ 'class': 'InvalidParameterCombination', 'data': {} }"
+
#define QERR_INVALID_PARAMETER_TYPE \
"{ 'class': 'InvalidParameterType', 'data': { 'name': %s,'expected': %s } }"
@@ -132,14 +153,11 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_IO_ERROR \
"{ 'class': 'IOError', 'data': {} }"
-#define QERR_JSON_PARSING \
- "{ 'class': 'JSONParsing', 'data': {} }"
-
#define QERR_JSON_PARSE_ERROR \
"{ 'class': 'JSONParseError', 'data': { 'message': %s } }"
-#define QERR_BUFFER_OVERRUN \
- "{ 'class': 'BufferOverrun', 'data': {} }"
+#define QERR_JSON_PARSING \
+ "{ 'class': 'JSONParsing', 'data': {} }"
#define QERR_KVM_MISSING_CAP \
"{ 'class': 'KVMMissingCap', 'data': { 'capability': %s, 'feature': %s } }"
@@ -153,6 +171,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_NO_BUS_FOR_DEVICE \
"{ 'class': 'NoBusForDevice', 'data': { 'device': %s, 'bus': %s } }"
+#define QERR_NOT_SUPPORTED \
+ "{ 'class': 'NotSupported', 'data': {} }"
+
#define QERR_OPEN_FILE_FAILED \
"{ 'class': 'OpenFileFailed', 'data': { 'filename': %s } }"
@@ -174,6 +195,12 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_PROPERTY_VALUE_OUT_OF_RANGE \
"{ 'class': 'PropertyValueOutOfRange', 'data': { 'device': %s, 'property': %s, 'value': %"PRId64", 'min': %"PRId64", 'max': %"PRId64" } }"
+#define QERR_QGA_COMMAND_FAILED \
+ "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
+
+#define QERR_QGA_LOGGING_FAILED \
+ "{ 'class': 'QgaLoggingFailed', 'data': {} }"
+
#define QERR_QMP_BAD_INPUT_OBJECT \
"{ 'class': 'QMPBadInputObject', 'data': { 'expected': %s } }"
@@ -189,37 +216,22 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_SET_PASSWD_FAILED \
"{ 'class': 'SetPasswdFailed', 'data': {} }"
-#define QERR_ADD_CLIENT_FAILED \
- "{ 'class': 'AddClientFailed', 'data': {} }"
-
#define QERR_TOO_MANY_FILES \
"{ 'class': 'TooManyFiles', 'data': {} }"
#define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }"
-#define QERR_UNSUPPORTED \
- "{ 'class': 'Unsupported', 'data': {} }"
-
#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
"{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+#define QERR_UNSUPPORTED \
+ "{ 'class': 'Unsupported', 'data': {} }"
+
#define QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION \
"{ 'class': 'VirtFSFeatureBlocksMigration', 'data': { 'path': %s, 'tag': %s } }"
#define QERR_VNC_SERVER_FAILED \
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
-#define QERR_FEATURE_DISABLED \
- "{ 'class': 'FeatureDisabled', 'data': { 'name': %s } }"
-
-#define QERR_QGA_LOGGING_FAILED \
- "{ 'class': 'QgaLoggingFailed', 'data': {} }"
-
-#define QERR_QGA_COMMAND_FAILED \
- "{ 'class': 'QgaCommandFailed', 'data': { 'message': %s } }"
-
-#define QERR_INVALID_PARAMETER_COMBINATION \
- "{ 'class': 'InvalidParameterCombination', 'data': {} }"
-
#endif /* QERROR_H */
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7e3f4b9a59..b5e2ab8574 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -84,10 +84,7 @@ EQMP
{
.name = "eject",
.args_type = "force:-f,device:B",
- .params = "[-f] device",
- .help = "eject a removable medium (use -f to force it)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_eject,
+ .mhandler.cmd_new = qmp_marshal_input_eject,
},
SQMP
@@ -113,10 +110,7 @@ EQMP
{
.name = "change",
.args_type = "device:B,target:F,arg:s?",
- .params = "device filename [format]",
- .help = "change a removable medium, optional format",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_change,
+ .mhandler.cmd_new = qmp_marshal_input_change,
},
SQMP
@@ -655,6 +649,24 @@ Example:
EQMP
{
+ .name = "block_stream",
+ .args_type = "device:B,base:s?",
+ .mhandler.cmd_new = qmp_marshal_input_block_stream,
+ },
+
+ {
+ .name = "block_job_set_speed",
+ .args_type = "device:B,value:o",
+ .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
+ },
+
+ {
+ .name = "block_job_cancel",
+ .args_type = "device:B",
+ .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
+ },
+
+ {
.name = "blockdev-snapshot-sync",
.args_type = "device:B,snapshot-file:s,format:s?",
.mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
@@ -813,10 +825,7 @@ EQMP
{
.name = "block_set_io_throttle",
.args_type = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l",
- .params = "device bps bps_rd bps_wr iops iops_rd iops_wr",
- .help = "change I/O throttle limits for a block drive",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_io_throttle,
+ .mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
},
SQMP
@@ -851,10 +860,7 @@ EQMP
{
.name = "set_password",
.args_type = "protocol:s,password:s,connected:s?",
- .params = "protocol password action-if-connected",
- .help = "set spice/vnc password",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = set_password,
+ .mhandler.cmd_new = qmp_marshal_input_set_password,
},
SQMP
@@ -880,10 +886,7 @@ EQMP
{
.name = "expire_password",
.args_type = "protocol:s,time:s",
- .params = "protocol time",
- .help = "set spice/vnc password expire-time",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = expire_password,
+ .mhandler.cmd_new = qmp_marshal_input_expire_password,
},
SQMP
@@ -2011,6 +2014,12 @@ EQMP
},
{
+ .name = "query-block-jobs",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_block_jobs,
+ },
+
+ {
.name = "qom-list",
.args_type = "path:s",
.mhandler.cmd_new = qmp_marshal_input_qom_list,
@@ -2027,3 +2036,14 @@ EQMP
.args_type = "path:s,property:s",
.mhandler.cmd_new = qmp_qom_get,
},
+
+ {
+ .name = "change-vnc-password",
+ .args_type = "password:s",
+ .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
+ },
+ {
+ .name = "qom-list-types",
+ .args_type = "implements:s?,abstract:b?",
+ .mhandler.cmd_new = qmp_marshal_input_qom_list_types,
+ },
diff --git a/qmp.c b/qmp.c
index c74dde6c90..45052cc978 100644
--- a/qmp.c
+++ b/qmp.c
@@ -16,11 +16,14 @@
#include "qemu-common.h"
#include "sysemu.h"
#include "qmp-commands.h"
+#include "ui/qemu-spice.h"
+#include "ui/vnc.h"
#include "kvm.h"
#include "arch_init.h"
#include "hw/qdev.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qmp-output-visitor.h"
+#include "blockdev.h"
NameInfo *qmp_query_name(Error **errp)
{
@@ -133,7 +136,8 @@ static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
Error **err = opaque;
if (!error_is_set(err) && bdrv_key_required(bs)) {
- error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+ error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs),
+ bdrv_get_encrypted_filename(bs));
}
}
@@ -160,23 +164,23 @@ void qmp_cont(Error **errp)
vm_start();
}
-DevicePropertyInfoList *qmp_qom_list(const char *path, Error **errp)
+ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
{
- DeviceState *dev;
+ Object *obj;
bool ambiguous = false;
- DevicePropertyInfoList *props = NULL;
- DeviceProperty *prop;
+ ObjectPropertyInfoList *props = NULL;
+ ObjectProperty *prop;
- dev = qdev_resolve_path(path, &ambiguous);
- if (dev == NULL) {
+ obj = object_resolve_path(path, &ambiguous);
+ if (obj == NULL) {
error_set(errp, QERR_DEVICE_NOT_FOUND, path);
return NULL;
}
- QTAILQ_FOREACH(prop, &dev->properties, node) {
- DevicePropertyInfoList *entry = g_malloc0(sizeof(*entry));
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ ObjectPropertyInfoList *entry = g_malloc0(sizeof(*entry));
- entry->value = g_malloc0(sizeof(DevicePropertyInfo));
+ entry->value = g_malloc0(sizeof(ObjectPropertyInfo));
entry->next = props;
props = entry;
@@ -195,16 +199,16 @@ int qmp_qom_set(Monitor *mon, const QDict *qdict, QObject **ret)
QObject *value = qdict_get(qdict, "value");
Error *local_err = NULL;
QmpInputVisitor *mi;
- DeviceState *dev;
+ Object *obj;
- dev = qdev_resolve_path(path, NULL);
- if (!dev) {
+ obj = object_resolve_path(path, NULL);
+ if (!obj) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
}
mi = qmp_input_visitor_new(value);
- qdev_property_set(dev, qmp_input_get_visitor(mi), property, &local_err);
+ object_property_set(obj, qmp_input_get_visitor(mi), property, &local_err);
qmp_input_visitor_cleanup(mi);
@@ -224,16 +228,16 @@ int qmp_qom_get(Monitor *mon, const QDict *qdict, QObject **ret)
const char *property = qdict_get_str(qdict, "property");
Error *local_err = NULL;
QmpOutputVisitor *mo;
- DeviceState *dev;
+ Object *obj;
- dev = qdev_resolve_path(path, NULL);
- if (!dev) {
+ obj = object_resolve_path(path, NULL);
+ if (!obj) {
error_set(&local_err, QERR_DEVICE_NOT_FOUND, path);
goto out;
}
mo = qmp_output_visitor_new();
- qdev_property_get(dev, qmp_output_get_visitor(mo), property, &local_err);
+ object_property_get(obj, qmp_output_get_visitor(mo), property, &local_err);
if (!local_err) {
*ret = qmp_output_get_qobject(mo);
}
@@ -249,3 +253,172 @@ out:
return 0;
}
+
+void qmp_set_password(const char *protocol, const char *password,
+ bool has_connected, const char *connected, Error **errp)
+{
+ int disconnect_if_connected = 0;
+ int fail_if_connected = 0;
+ int rc;
+
+ if (has_connected) {
+ if (strcmp(connected, "fail") == 0) {
+ fail_if_connected = 1;
+ } else if (strcmp(connected, "disconnect") == 0) {
+ disconnect_if_connected = 1;
+ } else if (strcmp(connected, "keep") == 0) {
+ /* nothing */
+ } else {
+ error_set(errp, QERR_INVALID_PARAMETER, "connected");
+ return;
+ }
+ }
+
+ if (strcmp(protocol, "spice") == 0) {
+ if (!using_spice) {
+ /* correct one? spice isn't a device ,,, */
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
+ return;
+ }
+ rc = qemu_spice_set_passwd(password, fail_if_connected,
+ disconnect_if_connected);
+ if (rc != 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ if (strcmp(protocol, "vnc") == 0) {
+ if (fail_if_connected || disconnect_if_connected) {
+ /* vnc supports "connected=keep" only */
+ error_set(errp, QERR_INVALID_PARAMETER, "connected");
+ return;
+ }
+ /* Note that setting an empty password will not disable login through
+ * this interface. */
+ rc = vnc_display_password(NULL, password);
+ if (rc < 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ error_set(errp, QERR_INVALID_PARAMETER, "protocol");
+}
+
+void qmp_expire_password(const char *protocol, const char *whenstr,
+ Error **errp)
+{
+ time_t when;
+ int rc;
+
+ if (strcmp(whenstr, "now") == 0) {
+ when = 0;
+ } else if (strcmp(whenstr, "never") == 0) {
+ when = TIME_MAX;
+ } else if (whenstr[0] == '+') {
+ when = time(NULL) + strtoull(whenstr+1, NULL, 10);
+ } else {
+ when = strtoull(whenstr, NULL, 10);
+ }
+
+ if (strcmp(protocol, "spice") == 0) {
+ if (!using_spice) {
+ /* correct one? spice isn't a device ,,, */
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, "spice");
+ return;
+ }
+ rc = qemu_spice_set_pw_expire(when);
+ if (rc != 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ if (strcmp(protocol, "vnc") == 0) {
+ rc = vnc_display_pw_expire(NULL, when);
+ if (rc != 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+ return;
+ }
+
+ error_set(errp, QERR_INVALID_PARAMETER, "protocol");
+}
+
+#ifdef CONFIG_VNC
+void qmp_change_vnc_password(const char *password, Error **errp)
+{
+ if (vnc_display_password(NULL, password) < 0) {
+ error_set(errp, QERR_SET_PASSWD_FAILED);
+ }
+}
+
+static void qmp_change_vnc_listen(const char *target, Error **err)
+{
+ if (vnc_display_open(NULL, target) < 0) {
+ error_set(err, QERR_VNC_SERVER_FAILED, target);
+ }
+}
+
+static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
+ Error **errp)
+{
+ if (strcmp(target, "passwd") == 0 || strcmp(target, "password") == 0) {
+ if (!has_arg) {
+ error_set(errp, QERR_MISSING_PARAMETER, "password");
+ } else {
+ qmp_change_vnc_password(arg, errp);
+ }
+ } else {
+ qmp_change_vnc_listen(target, errp);
+ }
+}
+#else
+void qmp_change_vnc_password(const char *password, Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+}
+static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
+ Error **errp)
+{
+ error_set(errp, QERR_FEATURE_DISABLED, "vnc");
+}
+#endif /* !CONFIG_VNC */
+
+void qmp_change(const char *device, const char *target,
+ bool has_arg, const char *arg, Error **err)
+{
+ if (strcmp(device, "vnc") == 0) {
+ qmp_change_vnc(target, has_arg, arg, err);
+ } else {
+ qmp_change_blockdev(device, target, has_arg, arg, err);
+ }
+}
+
+static void qom_list_types_tramp(ObjectClass *klass, void *data)
+{
+ ObjectTypeInfoList *e, **pret = data;
+ ObjectTypeInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ info->name = g_strdup(object_class_get_name(klass));
+
+ e = g_malloc0(sizeof(*e));
+ e->value = info;
+ e->next = *pret;
+ *pret = e;
+}
+
+ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
+ const char *implements,
+ bool has_abstract,
+ bool abstract,
+ Error **errp)
+{
+ ObjectTypeInfoList *ret = NULL;
+
+ object_class_foreach(qom_list_types_tramp, implements, abstract, &ret);
+
+ return ret;
+}
diff --git a/qom/Makefile b/qom/Makefile
new file mode 100644
index 0000000000..f33f0be8c9
--- /dev/null
+++ b/qom/Makefile
@@ -0,0 +1 @@
+qom-y = object.o container.o
diff --git a/qom/container.c b/qom/container.c
new file mode 100644
index 0000000000..946cbff90f
--- /dev/null
+++ b/qom/container.c
@@ -0,0 +1,27 @@
+/*
+ * Device Container
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/object.h"
+#include "module.h"
+
+static TypeInfo container_info = {
+ .name = "container",
+ .instance_size = sizeof(Object),
+ .parent = TYPE_OBJECT,
+};
+
+static void container_init(void)
+{
+ type_register_static(&container_info);
+}
+
+device_init(container_init);
diff --git a/qom/object.c b/qom/object.c
new file mode 100644
index 0000000000..4261944849
--- /dev/null
+++ b/qom/object.c
@@ -0,0 +1,984 @@
+/*
+ * QEMU Object Model
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/object.h"
+#include "qemu-common.h"
+#include "qapi/qapi-visit-core.h"
+#include "hw/qdev.h"
+// FIXME remove above
+
+#define MAX_INTERFACES 32
+
+typedef struct InterfaceImpl InterfaceImpl;
+typedef struct TypeImpl TypeImpl;
+
+struct InterfaceImpl
+{
+ const char *parent;
+ void (*interface_initfn)(ObjectClass *class, void *data);
+ TypeImpl *type;
+};
+
+struct TypeImpl
+{
+ const char *name;
+
+ size_t class_size;
+
+ size_t instance_size;
+
+ void (*class_init)(ObjectClass *klass, void *data);
+ void (*class_finalize)(ObjectClass *klass, void *data);
+
+ void *class_data;
+
+ void (*instance_init)(Object *obj);
+ void (*instance_finalize)(Object *obj);
+
+ bool abstract;
+
+ const char *parent;
+ TypeImpl *parent_type;
+
+ ObjectClass *class;
+
+ int num_interfaces;
+ InterfaceImpl interfaces[MAX_INTERFACES];
+};
+
+typedef struct Interface
+{
+ Object parent;
+ Object *obj;
+} Interface;
+
+#define INTERFACE(obj) OBJECT_CHECK(Interface, obj, TYPE_INTERFACE)
+
+static GHashTable *type_table_get(void)
+{
+ static GHashTable *type_table;
+
+ if (type_table == NULL) {
+ type_table = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ return type_table;
+}
+
+static void type_table_add(TypeImpl *ti)
+{
+ g_hash_table_insert(type_table_get(), (void *)ti->name, ti);
+}
+
+static TypeImpl *type_table_lookup(const char *name)
+{
+ return g_hash_table_lookup(type_table_get(), name);
+}
+
+TypeImpl *type_register(const TypeInfo *info)
+{
+ TypeImpl *ti = g_malloc0(sizeof(*ti));
+
+ g_assert(info->name != NULL);
+
+ if (type_table_lookup(info->name) != NULL) {
+ fprintf(stderr, "Registering `%s' which already exists\n", info->name);
+ abort();
+ }
+
+ ti->name = g_strdup(info->name);
+ ti->parent = g_strdup(info->parent);
+
+ ti->class_size = info->class_size;
+ ti->instance_size = info->instance_size;
+
+ ti->class_init = info->class_init;
+ ti->class_finalize = info->class_finalize;
+ ti->class_data = info->class_data;
+
+ ti->instance_init = info->instance_init;
+ ti->instance_finalize = info->instance_finalize;
+
+ ti->abstract = info->abstract;
+
+ if (info->interfaces) {
+ int i;
+
+ for (i = 0; info->interfaces[i].type; i++) {
+ ti->interfaces[i].parent = info->interfaces[i].type;
+ ti->interfaces[i].interface_initfn = info->interfaces[i].interface_initfn;
+ ti->num_interfaces++;
+ }
+ }
+
+ type_table_add(ti);
+
+ return ti;
+}
+
+TypeImpl *type_register_static(const TypeInfo *info)
+{
+ return type_register(info);
+}
+
+static TypeImpl *type_get_by_name(const char *name)
+{
+ if (name == NULL) {
+ return NULL;
+ }
+
+ return type_table_lookup(name);
+}
+
+static TypeImpl *type_get_parent(TypeImpl *type)
+{
+ if (!type->parent_type && type->parent) {
+ type->parent_type = type_get_by_name(type->parent);
+ g_assert(type->parent_type != NULL);
+ }
+
+ return type->parent_type;
+}
+
+static bool type_has_parent(TypeImpl *type)
+{
+ return (type->parent != NULL);
+}
+
+static size_t type_class_get_size(TypeImpl *ti)
+{
+ if (ti->class_size) {
+ return ti->class_size;
+ }
+
+ if (type_has_parent(ti)) {
+ return type_class_get_size(type_get_parent(ti));
+ }
+
+ return sizeof(ObjectClass);
+}
+
+static void type_class_interface_init(TypeImpl *ti, InterfaceImpl *iface)
+{
+ TypeInfo info = {
+ .instance_size = sizeof(Interface),
+ .parent = iface->parent,
+ .class_size = sizeof(InterfaceClass),
+ .class_init = iface->interface_initfn,
+ .abstract = true,
+ };
+ char *name = g_strdup_printf("<%s::%s>", ti->name, iface->parent);
+
+ info.name = name;
+ iface->type = type_register(&info);
+ g_free(name);
+}
+
+static void type_class_init(TypeImpl *ti)
+{
+ size_t class_size = sizeof(ObjectClass);
+ int i;
+
+ if (ti->class) {
+ return;
+ }
+
+ ti->class_size = type_class_get_size(ti);
+
+ ti->class = g_malloc0(ti->class_size);
+ ti->class->type = ti;
+
+ if (type_has_parent(ti)) {
+ TypeImpl *parent = type_get_parent(ti);
+
+ type_class_init(parent);
+
+ class_size = parent->class_size;
+ g_assert(parent->class_size <= ti->class_size);
+
+ memcpy((void *)ti->class + sizeof(ObjectClass),
+ (void *)parent->class + sizeof(ObjectClass),
+ parent->class_size - sizeof(ObjectClass));
+ }
+
+ memset((void *)ti->class + class_size, 0, ti->class_size - class_size);
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ type_class_interface_init(ti, &ti->interfaces[i]);
+ }
+
+ if (ti->class_init) {
+ ti->class_init(ti->class, ti->class_data);
+ }
+}
+
+static void object_interface_init(Object *obj, InterfaceImpl *iface)
+{
+ TypeImpl *ti = iface->type;
+ Interface *iface_obj;
+
+ iface_obj = INTERFACE(object_new(ti->name));
+ iface_obj->obj = obj;
+
+ obj->interfaces = g_slist_prepend(obj->interfaces, iface_obj);
+}
+
+static void object_init_with_type(Object *obj, TypeImpl *ti)
+{
+ int i;
+
+ if (type_has_parent(ti)) {
+ object_init_with_type(obj, type_get_parent(ti));
+ }
+
+ for (i = 0; i < ti->num_interfaces; i++) {
+ object_interface_init(obj, &ti->interfaces[i]);
+ }
+
+ if (ti->instance_init) {
+ ti->instance_init(obj);
+ }
+}
+
+void object_initialize_with_type(void *data, TypeImpl *type)
+{
+ Object *obj = data;
+
+ g_assert(type != NULL);
+ g_assert(type->instance_size >= sizeof(ObjectClass));
+
+ type_class_init(type);
+ g_assert(type->abstract == false);
+
+ memset(obj, 0, type->instance_size);
+ obj->class = type->class;
+ QTAILQ_INIT(&obj->properties);
+ object_init_with_type(obj, type);
+}
+
+void object_initialize(void *data, const char *typename)
+{
+ TypeImpl *type = type_get_by_name(typename);
+
+ object_initialize_with_type(data, type);
+}
+
+static void object_property_del_all(Object *obj)
+{
+ while (!QTAILQ_EMPTY(&obj->properties)) {
+ ObjectProperty *prop = QTAILQ_FIRST(&obj->properties);
+
+ QTAILQ_REMOVE(&obj->properties, prop, node);
+
+ if (prop->release) {
+ prop->release(obj, prop->name, prop->opaque);
+ }
+
+ g_free(prop->name);
+ g_free(prop->type);
+ g_free(prop);
+ }
+}
+
+static void object_property_del_child(Object *obj, Object *child, Error **errp)
+{
+ ObjectProperty *prop;
+
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ if (prop->opaque == child) {
+ object_property_del(obj, prop->name, errp);
+ }
+ }
+}
+
+void object_unparent(Object *obj)
+{
+ if (obj->parent) {
+ object_property_del_child(obj->parent, obj, NULL);
+ }
+}
+
+static void object_deinit(Object *obj, TypeImpl *type)
+{
+ if (type->instance_finalize) {
+ type->instance_finalize(obj);
+ }
+
+ while (obj->interfaces) {
+ Interface *iface_obj = obj->interfaces->data;
+ obj->interfaces = g_slist_delete_link(obj->interfaces, obj->interfaces);
+ object_delete(OBJECT(iface_obj));
+ }
+
+ if (type_has_parent(type)) {
+ object_deinit(obj, type_get_parent(type));
+ }
+
+ object_unparent(obj);
+}
+
+void object_finalize(void *data)
+{
+ Object *obj = data;
+ TypeImpl *ti = obj->class->type;
+
+ object_deinit(obj, ti);
+ object_property_del_all(obj);
+
+ g_assert(obj->ref == 0);
+}
+
+Object *object_new_with_type(Type type)
+{
+ Object *obj;
+
+ g_assert(type != NULL);
+
+ obj = g_malloc(type->instance_size);
+ object_initialize_with_type(obj, type);
+ object_ref(obj);
+
+ return obj;
+}
+
+Object *object_new(const char *typename)
+{
+ TypeImpl *ti = type_get_by_name(typename);
+
+ return object_new_with_type(ti);
+}
+
+void object_delete(Object *obj)
+{
+ object_unref(obj);
+ g_assert(obj->ref == 0);
+ g_free(obj);
+}
+
+static bool object_is_type(Object *obj, const char *typename)
+{
+ TypeImpl *target_type = type_get_by_name(typename);
+ TypeImpl *type = obj->class->type;
+ GSList *i;
+
+ /* Check if typename is a direct ancestor of type */
+ while (type) {
+ if (type == target_type) {
+ return true;
+ }
+
+ type = type_get_parent(type);
+ }
+
+ /* Check if obj has an interface of typename */
+ for (i = obj->interfaces; i; i = i->next) {
+ Interface *iface = i->data;
+
+ if (object_is_type(OBJECT(iface), typename)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Object *object_dynamic_cast(Object *obj, const char *typename)
+{
+ GSList *i;
+
+ /* Check if typename is a direct ancestor */
+ if (object_is_type(obj, typename)) {
+ return obj;
+ }
+
+ /* Check if obj has an interface of typename */
+ for (i = obj->interfaces; i; i = i->next) {
+ Interface *iface = i->data;
+
+ if (object_is_type(OBJECT(iface), typename)) {
+ return OBJECT(iface);
+ }
+ }
+
+ /* Check if obj is an interface and its containing object is a direct
+ * ancestor of typename */
+ if (object_is_type(obj, TYPE_INTERFACE)) {
+ Interface *iface = INTERFACE(obj);
+
+ if (object_is_type(iface->obj, typename)) {
+ return iface->obj;
+ }
+ }
+
+ return NULL;
+}
+
+
+static void register_interface(void)
+{
+ static TypeInfo interface_info = {
+ .name = TYPE_INTERFACE,
+ .instance_size = sizeof(Interface),
+ .abstract = true,
+ };
+
+ type_register_static(&interface_info);
+}
+
+device_init(register_interface);
+
+Object *object_dynamic_cast_assert(Object *obj, const char *typename)
+{
+ Object *inst;
+
+ inst = object_dynamic_cast(obj, typename);
+
+ if (!inst) {
+ fprintf(stderr, "Object %p is not an instance of type %s\n",
+ obj, typename);
+ abort();
+ }
+
+ return inst;
+}
+
+ObjectClass *object_class_dynamic_cast(ObjectClass *class,
+ const char *typename)
+{
+ TypeImpl *target_type = type_get_by_name(typename);
+ TypeImpl *type = class->type;
+
+ while (type) {
+ if (type == target_type) {
+ return class;
+ }
+
+ type = type_get_parent(type);
+ }
+
+ return NULL;
+}
+
+ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
+ const char *typename)
+{
+ ObjectClass *ret = object_class_dynamic_cast(class, typename);
+
+ if (!ret) {
+ fprintf(stderr, "Object %p is not an instance of type %s\n",
+ class, typename);
+ abort();
+ }
+
+ return ret;
+}
+
+const char *object_get_typename(Object *obj)
+{
+ return obj->class->type->name;
+}
+
+ObjectClass *object_get_class(Object *obj)
+{
+ return obj->class;
+}
+
+const char *object_class_get_name(ObjectClass *klass)
+{
+ return klass->type->name;
+}
+
+ObjectClass *object_class_by_name(const char *typename)
+{
+ TypeImpl *type = type_get_by_name(typename);
+
+ if (!type) {
+ return NULL;
+ }
+
+ type_class_init(type);
+
+ return type->class;
+}
+
+typedef struct OCFData
+{
+ void (*fn)(ObjectClass *klass, void *opaque);
+ const char *implements_type;
+ bool include_abstract;
+ void *opaque;
+} OCFData;
+
+static void object_class_foreach_tramp(gpointer key, gpointer value,
+ gpointer opaque)
+{
+ OCFData *data = opaque;
+ TypeImpl *type = value;
+ ObjectClass *k;
+
+ type_class_init(type);
+ k = type->class;
+
+ if (!data->include_abstract && type->abstract) {
+ return;
+ }
+
+ if (data->implements_type &&
+ !object_class_dynamic_cast(k, data->implements_type)) {
+ return;
+ }
+
+ data->fn(k, data->opaque);
+}
+
+void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
+ const char *implements_type, bool include_abstract,
+ void *opaque)
+{
+ OCFData data = { fn, implements_type, include_abstract, opaque };
+
+ g_hash_table_foreach(type_table_get(), object_class_foreach_tramp, &data);
+}
+
+void object_ref(Object *obj)
+{
+ obj->ref++;
+}
+
+void object_unref(Object *obj)
+{
+ g_assert(obj->ref > 0);
+ obj->ref--;
+
+ /* parent always holds a reference to its children */
+ if (obj->ref == 0) {
+ object_finalize(obj);
+ }
+}
+
+void object_property_add(Object *obj, const char *name, const char *type,
+ ObjectPropertyAccessor *get,
+ ObjectPropertyAccessor *set,
+ ObjectPropertyRelease *release,
+ void *opaque, Error **errp)
+{
+ ObjectProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->name = g_strdup(name);
+ prop->type = g_strdup(type);
+
+ prop->get = get;
+ prop->set = set;
+ prop->release = release;
+ prop->opaque = opaque;
+
+ QTAILQ_INSERT_TAIL(&obj->properties, prop, node);
+}
+
+static ObjectProperty *object_property_find(Object *obj, const char *name)
+{
+ ObjectProperty *prop;
+
+ QTAILQ_FOREACH(prop, &obj->properties, node) {
+ if (strcmp(prop->name, name) == 0) {
+ return prop;
+ }
+ }
+
+ return NULL;
+}
+
+void object_property_del(Object *obj, const char *name, Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ QTAILQ_REMOVE(&obj->properties, prop, node);
+
+ prop->release(obj, prop->name, prop->opaque);
+
+ g_free(prop->name);
+ g_free(prop->type);
+ g_free(prop);
+}
+
+void object_property_get(Object *obj, Visitor *v, const char *name,
+ Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return;
+ }
+
+ if (!prop->get) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
+ prop->get(obj, v, prop->opaque, name, errp);
+ }
+}
+
+void object_property_set(Object *obj, Visitor *v, const char *name,
+ Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return;
+ }
+
+ if (!prop->set) {
+ error_set(errp, QERR_PERMISSION_DENIED);
+ } else {
+ prop->set(obj, v, prop->opaque, name, errp);
+ }
+}
+
+const char *object_property_get_type(Object *obj, const char *name, Error **errp)
+{
+ ObjectProperty *prop = object_property_find(obj, name);
+
+ if (prop == NULL) {
+ error_set(errp, QERR_PROPERTY_NOT_FOUND, "", name);
+ return NULL;
+ }
+
+ return prop->type;
+}
+
+Object *object_get_root(void)
+{
+ static Object *root;
+
+ if (!root) {
+ root = object_new("container");
+ }
+
+ return root;
+}
+
+static void object_get_child_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object *child = opaque;
+ gchar *path;
+
+ path = object_get_canonical_path(child);
+ visit_type_str(v, &path, name, errp);
+ g_free(path);
+}
+
+static void object_finalize_child_property(Object *obj, const char *name,
+ void *opaque)
+{
+ Object *child = opaque;
+
+ object_unref(child);
+}
+
+void object_property_add_child(Object *obj, const char *name,
+ Object *child, Error **errp)
+{
+ gchar *type;
+
+ type = g_strdup_printf("child<%s>", object_get_typename(OBJECT(child)));
+
+ object_property_add(obj, name, type, object_get_child_property,
+ NULL, object_finalize_child_property, child, errp);
+
+ object_ref(child);
+ g_assert(child->parent == NULL);
+ child->parent = obj;
+
+ g_free(type);
+}
+
+static void object_get_link_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object **child = opaque;
+ gchar *path;
+
+ if (*child) {
+ path = object_get_canonical_path(*child);
+ visit_type_str(v, &path, name, errp);
+ g_free(path);
+ } else {
+ path = (gchar *)"";
+ visit_type_str(v, &path, name, errp);
+ }
+}
+
+static void object_set_link_property(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ Object **child = opaque;
+ bool ambiguous = false;
+ const char *type;
+ char *path;
+
+ type = object_property_get_type(obj, name, NULL);
+
+ visit_type_str(v, &path, name, errp);
+
+ if (*child) {
+ object_unref(*child);
+ }
+
+ if (strcmp(path, "") != 0) {
+ Object *target;
+
+ target = object_resolve_path(path, &ambiguous);
+ if (target) {
+ gchar *target_type;
+
+ target_type = g_strdup(&type[5]);
+ target_type[strlen(target_type) - 2] = 0;
+
+ if (object_dynamic_cast(target, target_type)) {
+ object_ref(target);
+ *child = target;
+ } else {
+ error_set(errp, QERR_INVALID_PARAMETER_TYPE, name, type);
+ }
+
+ g_free(target_type);
+ } else {
+ error_set(errp, QERR_DEVICE_NOT_FOUND, path);
+ }
+ } else {
+ *child = NULL;
+ }
+
+ g_free(path);
+}
+
+void object_property_add_link(Object *obj, const char *name,
+ const char *type, Object **child,
+ Error **errp)
+{
+ gchar *full_type;
+
+ full_type = g_strdup_printf("link<%s>", type);
+
+ object_property_add(obj, name, full_type,
+ object_get_link_property,
+ object_set_link_property,
+ NULL, child, errp);
+
+ g_free(full_type);
+}
+
+gchar *object_get_canonical_path(Object *obj)
+{
+ Object *root = object_get_root();
+ char *newpath = NULL, *path = NULL;
+
+ while (obj != root) {
+ ObjectProperty *prop = NULL;
+
+ g_assert(obj->parent != NULL);
+
+ QTAILQ_FOREACH(prop, &obj->parent->properties, node) {
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ if (prop->opaque == obj) {
+ if (path) {
+ newpath = g_strdup_printf("%s/%s", prop->name, path);
+ g_free(path);
+ path = newpath;
+ } else {
+ path = g_strdup(prop->name);
+ }
+ break;
+ }
+ }
+
+ g_assert(prop != NULL);
+
+ obj = obj->parent;
+ }
+
+ newpath = g_strdup_printf("/%s", path);
+ g_free(path);
+
+ return newpath;
+}
+
+static Object *object_resolve_abs_path(Object *parent,
+ gchar **parts,
+ int index)
+{
+ ObjectProperty *prop;
+ Object *child;
+
+ if (parts[index] == NULL) {
+ return parent;
+ }
+
+ if (strcmp(parts[index], "") == 0) {
+ return object_resolve_abs_path(parent, parts, index + 1);
+ }
+
+ prop = object_property_find(parent, parts[index]);
+ if (prop == NULL) {
+ return NULL;
+ }
+
+ child = NULL;
+ if (strstart(prop->type, "link<", NULL)) {
+ Object **pchild = prop->opaque;
+ if (*pchild) {
+ child = *pchild;
+ }
+ } else if (strstart(prop->type, "child<", NULL)) {
+ child = prop->opaque;
+ }
+
+ if (!child) {
+ return NULL;
+ }
+
+ return object_resolve_abs_path(child, parts, index + 1);
+}
+
+static Object *object_resolve_partial_path(Object *parent,
+ gchar **parts,
+ bool *ambiguous)
+{
+ Object *obj;
+ ObjectProperty *prop;
+
+ obj = object_resolve_abs_path(parent, parts, 0);
+
+ QTAILQ_FOREACH(prop, &parent->properties, node) {
+ Object *found;
+
+ if (!strstart(prop->type, "child<", NULL)) {
+ continue;
+ }
+
+ found = object_resolve_partial_path(prop->opaque, parts, ambiguous);
+ if (found) {
+ if (obj) {
+ if (ambiguous) {
+ *ambiguous = true;
+ }
+ return NULL;
+ }
+ obj = found;
+ }
+
+ if (ambiguous && *ambiguous) {
+ return NULL;
+ }
+ }
+
+ return obj;
+}
+
+Object *object_resolve_path(const char *path, bool *ambiguous)
+{
+ bool partial_path = true;
+ Object *obj;
+ gchar **parts;
+
+ parts = g_strsplit(path, "/", 0);
+ if (parts == NULL || parts[0] == NULL) {
+ g_strfreev(parts);
+ return object_get_root();
+ }
+
+ if (strcmp(parts[0], "") == 0) {
+ partial_path = false;
+ }
+
+ if (partial_path) {
+ if (ambiguous) {
+ *ambiguous = false;
+ }
+ obj = object_resolve_partial_path(object_get_root(), parts, ambiguous);
+ } else {
+ obj = object_resolve_abs_path(object_get_root(), parts, 1);
+ }
+
+ g_strfreev(parts);
+
+ return obj;
+}
+
+typedef struct StringProperty
+{
+ char *(*get)(Object *, Error **);
+ void (*set)(Object *, const char *, Error **);
+} StringProperty;
+
+static void object_property_get_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ StringProperty *prop = opaque;
+ char *value;
+
+ value = prop->get(obj, errp);
+ if (value) {
+ visit_type_str(v, &value, name, errp);
+ g_free(value);
+ }
+}
+
+static void object_property_set_str(Object *obj, Visitor *v, void *opaque,
+ const char *name, Error **errp)
+{
+ StringProperty *prop = opaque;
+ char *value;
+ Error *local_err = NULL;
+
+ visit_type_str(v, &value, name, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ prop->set(obj, value, errp);
+ g_free(value);
+}
+
+static void object_property_release_str(Object *obj, const char *name,
+ void *opaque)
+{
+ StringProperty *prop = opaque;
+ g_free(prop);
+}
+
+void object_property_add_str(Object *obj, const char *name,
+ char *(*get)(Object *, Error **),
+ void (*set)(Object *, const char *, Error **),
+ Error **errp)
+{
+ StringProperty *prop = g_malloc0(sizeof(*prop));
+
+ prop->get = get;
+ prop->set = set;
+
+ object_property_add(obj, name, "string",
+ get ? object_property_get_str : NULL,
+ set ? object_property_set_str : NULL,
+ object_property_release_str,
+ prop, errp);
+}
diff --git a/roms/SLOF b/roms/SLOF
-Subproject 32e3430c018ceb8413cb808477449d1968c4249
+Subproject ab062ff3b37c39649f2b0d94ed607adc6f6b3c7
diff --git a/scripts/check-qerror.sh b/scripts/check-qerror.sh
new file mode 100755
index 0000000000..af7fbd5249
--- /dev/null
+++ b/scripts/check-qerror.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# This script verifies that qerror definitions and table entries are
+# alphabetically ordered.
+
+check_order() {
+ errmsg=$1
+ shift
+
+ # sort -C verifies order but does not print a message. sort -c does print a
+ # message. These options are both in POSIX.
+ if ! "$@" | sort -C; then
+ echo "$errmsg"
+ "$@" | sort -c
+ exit 1
+ fi
+ return 0
+}
+
+check_order 'Definitions in qerror.h must be in alphabetical order:' \
+ grep '^#define QERR_' qerror.h
+check_order 'Entries in qerror.c:qerror_table must be in alphabetical order:' \
+ sed -n '/^static.*qerror_table\[\]/,/^};/s/QERR_/&/gp' qerror.c
diff --git a/sysemu.h b/sysemu.h
index ddef2bb0c1..9d5ce3398f 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -102,11 +102,9 @@ extern int vga_interface_type;
extern int graphic_width;
extern int graphic_height;
extern int graphic_depth;
-extern uint8_t irq0override;
extern DisplayType display_type;
extern const char *keyboard_layout;
extern int win2k_install_hack;
-extern int rtc_td_hack;
extern int alt_grab;
extern int ctrl_grab;
extern int usb_enabled;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 42c53a7d52..0d9b39ce21 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -382,6 +382,7 @@ enum arm_features {
ARM_FEATURE_VAPA, /* cp15 VA to PA lookups */
ARM_FEATURE_ARM_DIV, /* divide supported in ARM encoding */
ARM_FEATURE_VFP4, /* VFPv4 (implies that NEON is v2) */
+ ARM_FEATURE_GENERIC_TIMER,
};
static inline int arm_feature(CPUARMState *env, int feature)
@@ -432,6 +433,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
#define ARM_CPUID_ARM11MPCORE 0x410fb022
#define ARM_CPUID_CORTEXA8 0x410fc080
#define ARM_CPUID_CORTEXA9 0x410fc090
+#define ARM_CPUID_CORTEXA15 0x412fc0f1
#define ARM_CPUID_CORTEXM3 0x410fc231
#define ARM_CPUID_ANY 0xffffffff
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 00458fc892..ea4f35fb6c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -10,6 +10,16 @@
#if !defined(CONFIG_USER_ONLY)
#include "hw/loader.h"
#endif
+#include "sysemu.h"
+
+static uint32_t cortexa15_cp15_c0_c1[8] = {
+ 0x00001131, 0x00011011, 0x02010555, 0x00000000,
+ 0x10201105, 0x20000000, 0x01240000, 0x02102211
+};
+
+static uint32_t cortexa15_cp15_c0_c2[8] = {
+ 0x02101110, 0x13112111, 0x21232041, 0x11112131, 0x10011142, 0, 0, 0
+};
static uint32_t cortexa9_cp15_c0_c1[8] =
{ 0x1031, 0x11, 0x000, 0, 0x00100103, 0x20000000, 0x01230000, 0x00002111 };
@@ -158,6 +168,27 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
env->cp15.c0_ccsid[1] = 0x200fe015; /* 16k L1 icache. */
env->cp15.c1_sys = 0x00c50078;
break;
+ case ARM_CPUID_CORTEXA15:
+ set_feature(env, ARM_FEATURE_V7);
+ set_feature(env, ARM_FEATURE_VFP4);
+ set_feature(env, ARM_FEATURE_VFP_FP16);
+ set_feature(env, ARM_FEATURE_NEON);
+ set_feature(env, ARM_FEATURE_THUMB2EE);
+ set_feature(env, ARM_FEATURE_ARM_DIV);
+ set_feature(env, ARM_FEATURE_V7MP);
+ set_feature(env, ARM_FEATURE_GENERIC_TIMER);
+ env->vfp.xregs[ARM_VFP_FPSID] = 0x410430f0;
+ env->vfp.xregs[ARM_VFP_MVFR0] = 0x10110222;
+ env->vfp.xregs[ARM_VFP_MVFR1] = 0x11111111;
+ memcpy(env->cp15.c0_c1, cortexa15_cp15_c0_c1, 8 * sizeof(uint32_t));
+ memcpy(env->cp15.c0_c2, cortexa15_cp15_c0_c2, 8 * sizeof(uint32_t));
+ env->cp15.c0_cachetype = 0x8444c004;
+ env->cp15.c0_clid = 0x0a200023;
+ env->cp15.c0_ccsid[0] = 0x701fe00a; /* 32K L1 dcache */
+ env->cp15.c0_ccsid[1] = 0x201fe00a; /* 32K L1 icache */
+ env->cp15.c0_ccsid[2] = 0x711fe07a; /* 4096K L2 unified cache */
+ env->cp15.c1_sys = 0x00c50078;
+ break;
case ARM_CPUID_CORTEXM3:
set_feature(env, ARM_FEATURE_V7);
set_feature(env, ARM_FEATURE_M);
@@ -255,6 +286,7 @@ static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
void cpu_reset(CPUARMState *env)
{
uint32_t id;
+ uint32_t tmp = 0;
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
@@ -262,9 +294,11 @@ void cpu_reset(CPUARMState *env)
}
id = env->cp15.c0_cpuid;
+ tmp = env->cp15.c15_config_base_address;
memset(env, 0, offsetof(CPUARMState, breakpoints));
if (id)
cpu_reset_model_id(env, id);
+ env->cp15.c15_config_base_address = tmp;
#if defined (CONFIG_USER_ONLY)
env->uncached_cpsr = ARM_CPU_MODE_USR;
/* For user mode we must enable access to coprocessors */
@@ -413,6 +447,7 @@ static const struct arm_cpu_t arm_cpu_names[] = {
{ ARM_CPUID_CORTEXM3, "cortex-m3"},
{ ARM_CPUID_CORTEXA8, "cortex-a8"},
{ ARM_CPUID_CORTEXA9, "cortex-a9"},
+ { ARM_CPUID_CORTEXA15, "cortex-a15" },
{ ARM_CPUID_TI925T, "ti925t" },
{ ARM_CPUID_PXA250, "pxa250" },
{ ARM_CPUID_SA1100, "sa1100" },
@@ -667,8 +702,6 @@ uint32_t HELPER(get_r13_banked)(CPUState *env, uint32_t mode)
#else
-extern int semihosting_enabled;
-
/* Map CPU modes onto saved register banks. */
static inline int bank_number(CPUState *env, int mode)
{
@@ -1610,18 +1643,17 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
break;
case 8: /* MMU TLB control. */
switch (op2) {
- case 0: /* Invalidate all. */
- tlb_flush(env, 0);
+ case 0: /* Invalidate all (TLBIALL) */
+ tlb_flush(env, 1);
break;
- case 1: /* Invalidate single TLB entry. */
+ case 1: /* Invalidate single TLB entry by MVA and ASID (TLBIMVA) */
tlb_flush_page(env, val & TARGET_PAGE_MASK);
break;
- case 2: /* Invalidate on ASID. */
+ case 2: /* Invalidate by ASID (TLBIASID) */
tlb_flush(env, val == 0);
break;
- case 3: /* Invalidate single entry on MVA. */
- /* ??? This is like case 1, but ignores ASID. */
- tlb_flush(env, 1);
+ case 3: /* Invalidate single entry by MVA, all ASIDs (TLBIMVAA) */
+ tlb_flush_page(env, val & TARGET_PAGE_MASK);
break;
default:
goto bad_reg;
@@ -1762,7 +1794,11 @@ void HELPER(set_cp15)(CPUState *env, uint32_t insn, uint32_t val)
goto bad_reg;
}
break;
- case 14: /* Reserved. */
+ case 14: /* Generic timer */
+ if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
+ /* Dummy implementation: RAZ/WI for all */
+ break;
+ }
goto bad_reg;
case 15: /* Implementation specific. */
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
@@ -1939,6 +1975,7 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
case ARM_CPUID_CORTEXA8:
return 2;
case ARM_CPUID_CORTEXA9:
+ case ARM_CPUID_CORTEXA15:
return 0;
default:
goto bad_reg;
@@ -2059,11 +2096,26 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
goto bad_reg;
}
case 1: /* L2 cache */
- if (crm != 0) {
+ /* L2 Lockdown and Auxiliary control. */
+ switch (op2) {
+ case 0:
+ /* L2 cache lockdown (A8 only) */
+ return 0;
+ case 2:
+ /* L2 cache auxiliary control (A8) or control (A15) */
+ if (ARM_CPUID(env) == ARM_CPUID_CORTEXA15) {
+ /* Linux wants the number of processors from here.
+ * Might as well set the interrupt-controller bit too.
+ */
+ return ((smp_cpus - 1) << 24) | (1 << 23);
+ }
+ return 0;
+ case 3:
+ /* L2 cache extended control (A15) */
+ return 0;
+ default:
goto bad_reg;
}
- /* L2 Lockdown and Auxiliary control. */
- return 0;
default:
goto bad_reg;
}
@@ -2132,7 +2184,11 @@ uint32_t HELPER(get_cp15)(CPUState *env, uint32_t insn)
default:
goto bad_reg;
}
- case 14: /* Reserved. */
+ case 14: /* Generic timer */
+ if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
+ /* Dummy implementation: RAZ/WI for all */
+ return 0;
+ }
goto bad_reg;
case 15: /* Implementation specific. */
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
@@ -2786,7 +2842,7 @@ DO_VFP_cmp(d, float64)
float##fsz HELPER(name)(uint32_t x, void *fpstp) \
{ \
float_status *fpst = fpstp; \
- return sign##int32_to_##float##fsz(x, fpst); \
+ return sign##int32_to_##float##fsz((sign##int32_t)x, fpst); \
}
#define CONV_FTOI(name, fsz, sign, round) \
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 91a104ba0b..b9bfeaff70 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -27,6 +27,8 @@
#include "qemu-option.h"
#include "qemu-config.h"
+#include "hyperv.h"
+
/* feature flags taken from "Intel Processor Identification and the CPUID
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
* between feature naming conventions, aliases may be added.
@@ -716,6 +718,14 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
goto error;
}
x86_cpu_def->tsc_khz = tsc_freq / 1000;
+ } else if (!strcmp(featurestr, "hv_spinlocks")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ hyperv_set_spinlock_retries(numvalue);
} else {
fprintf(stderr, "unrecognized feature %s\n", featurestr);
goto error;
@@ -724,6 +734,10 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
check_cpuid = 1;
} else if (!strcmp(featurestr, "enforce")) {
check_cpuid = enforce_cpuid = 1;
+ } else if (!strcmp(featurestr, "hv_relaxed")) {
+ hyperv_enable_relaxed_timing(true);
+ } else if (!strcmp(featurestr, "hv_vapic")) {
+ hyperv_enable_vapic_recommended(true);
} else {
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
goto error;
diff --git a/target-i386/hyperv.c b/target-i386/hyperv.c
new file mode 100644
index 0000000000..f284e99772
--- /dev/null
+++ b/target-i386/hyperv.c
@@ -0,0 +1,64 @@
+/*
+ * QEMU Hyper-V support
+ *
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Author: Vadim Rozenfeld <vrozenfe@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "hyperv.h"
+
+static bool hyperv_vapic;
+static bool hyperv_relaxed_timing;
+static int hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
+
+void hyperv_enable_vapic_recommended(bool val)
+{
+ hyperv_vapic = val;
+}
+
+void hyperv_enable_relaxed_timing(bool val)
+{
+ hyperv_relaxed_timing = val;
+}
+
+void hyperv_set_spinlock_retries(int val)
+{
+ hyperv_spinlock_attempts = val;
+ if (hyperv_spinlock_attempts < 0xFFF) {
+ hyperv_spinlock_attempts = 0xFFF;
+ }
+}
+
+bool hyperv_enabled(void)
+{
+ return hyperv_hypercall_available() || hyperv_relaxed_timing_enabled();
+}
+
+bool hyperv_hypercall_available(void)
+{
+ if (hyperv_vapic ||
+ (hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY)) {
+ return true;
+ }
+ return false;
+}
+
+bool hyperv_vapic_recommended(void)
+{
+ return hyperv_vapic;
+}
+
+bool hyperv_relaxed_timing_enabled(void)
+{
+ return hyperv_relaxed_timing;
+}
+
+int hyperv_get_spinlock_retries(void)
+{
+ return hyperv_spinlock_attempts;
+}
diff --git a/target-i386/hyperv.h b/target-i386/hyperv.h
new file mode 100644
index 0000000000..bacb1d4373
--- /dev/null
+++ b/target-i386/hyperv.h
@@ -0,0 +1,45 @@
+/*
+ * QEMU Hyper-V support
+ *
+ * Copyright Red Hat, Inc. 2011
+ *
+ * Author: Vadim Rozenfeld <vrozenfe@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.
+ *
+ */
+
+#ifndef QEMU_HW_HYPERV_H
+#define QEMU_HW_HYPERV_H 1
+
+#include "qemu-common.h"
+#ifdef CONFIG_KVM
+#include <asm/hyperv.h>
+#endif
+
+#ifndef HYPERV_SPINLOCK_NEVER_RETRY
+#define HYPERV_SPINLOCK_NEVER_RETRY 0xFFFFFFFF
+#endif
+
+#ifndef KVM_CPUID_SIGNATURE_NEXT
+#define KVM_CPUID_SIGNATURE_NEXT 0x40000100
+#endif
+
+#if !defined(CONFIG_USER_ONLY) && defined(CONFIG_KVM)
+void hyperv_enable_vapic_recommended(bool val);
+void hyperv_enable_relaxed_timing(bool val);
+void hyperv_set_spinlock_retries(int val);
+#else
+static inline void hyperv_enable_vapic_recommended(bool val) { }
+static inline void hyperv_enable_relaxed_timing(bool val) { }
+static inline void hyperv_set_spinlock_retries(int val) { }
+#endif
+
+bool hyperv_enabled(void);
+bool hyperv_hypercall_available(void);
+bool hyperv_vapic_recommended(void);
+bool hyperv_relaxed_timing_enabled(void);
+int hyperv_get_spinlock_retries(void);
+
+#endif /* QEMU_HW_HYPERV_H */
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 04e65c5ea1..e41de394d2 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -29,6 +29,7 @@
#include "hw/pc.h"
#include "hw/apic.h"
#include "ioport.h"
+#include "hyperv.h"
//#define DEBUG_KVM
@@ -373,11 +374,16 @@ int kvm_arch_init_vcpu(CPUState *env)
cpuid_i = 0;
/* Paravirtualization CPUIDs */
- memcpy(signature, "KVMKVMKVM\0\0\0", 12);
c = &cpuid_data.entries[cpuid_i++];
memset(c, 0, sizeof(*c));
c->function = KVM_CPUID_SIGNATURE;
- c->eax = 0;
+ if (!hyperv_enabled()) {
+ memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+ c->eax = 0;
+ } else {
+ memcpy(signature, "Microsoft Hv", 12);
+ c->eax = HYPERV_CPUID_MIN;
+ }
c->ebx = signature[0];
c->ecx = signature[1];
c->edx = signature[2];
@@ -388,6 +394,54 @@ int kvm_arch_init_vcpu(CPUState *env)
c->eax = env->cpuid_kvm_features &
kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
+ if (hyperv_enabled()) {
+ memcpy(signature, "Hv#1\0\0\0\0\0\0\0\0", 12);
+ c->eax = signature[0];
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_VERSION;
+ c->eax = 0x00001bbc;
+ c->ebx = 0x00060001;
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_FEATURES;
+ if (hyperv_relaxed_timing_enabled()) {
+ c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+ }
+ if (hyperv_vapic_recommended()) {
+ c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+ c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
+ }
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
+ if (hyperv_relaxed_timing_enabled()) {
+ c->eax |= HV_X64_RELAXED_TIMING_RECOMMENDED;
+ }
+ if (hyperv_vapic_recommended()) {
+ c->eax |= HV_X64_APIC_ACCESS_RECOMMENDED;
+ }
+ c->ebx = hyperv_get_spinlock_retries();
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = HYPERV_CPUID_IMPLEMENT_LIMITS;
+ c->eax = 0x40;
+ c->ebx = 0x40;
+
+ c = &cpuid_data.entries[cpuid_i++];
+ memset(c, 0, sizeof(*c));
+ c->function = KVM_CPUID_SIGNATURE_NEXT;
+ memcpy(signature, "KVMKVMKVM\0\0\0", 12);
+ c->eax = 0;
+ c->ebx = signature[0];
+ c->ecx = signature[1];
+ c->edx = signature[2];
+ }
+
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
@@ -933,6 +987,13 @@ static int kvm_put_msrs(CPUState *env, int level)
kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
env->async_pf_en_msr);
}
+ if (hyperv_hypercall_available()) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
+ }
+ if (hyperv_vapic_recommended()) {
+ kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE, 0);
+ }
}
if (env->mcg_cap) {
int i;
@@ -1276,6 +1337,36 @@ static int kvm_get_mp_state(CPUState *env)
return 0;
}
+static int kvm_get_apic(CPUState *env)
+{
+ DeviceState *apic = env->apic_state;
+ struct kvm_lapic_state kapic;
+ int ret;
+
+ if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+ ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic);
+ if (ret < 0) {
+ return ret;
+ }
+
+ kvm_get_apic_state(apic, &kapic);
+ }
+ return 0;
+}
+
+static int kvm_put_apic(CPUState *env)
+{
+ DeviceState *apic = env->apic_state;
+ struct kvm_lapic_state kapic;
+
+ if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+ kvm_put_apic_state(apic, &kapic);
+
+ return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic);
+ }
+ return 0;
+}
+
static int kvm_put_vcpu_events(CPUState *env, int level)
{
struct kvm_vcpu_events events;
@@ -1449,6 +1540,10 @@ int kvm_arch_put_registers(CPUState *env, int level)
if (ret < 0) {
return ret;
}
+ ret = kvm_put_apic(env);
+ if (ret < 0) {
+ return ret;
+ }
}
ret = kvm_put_vcpu_events(env, level);
if (ret < 0) {
@@ -1496,6 +1591,10 @@ int kvm_arch_get_registers(CPUState *env)
if (ret < 0) {
return ret;
}
+ ret = kvm_get_apic(env);
+ if (ret < 0) {
+ return ret;
+ }
ret = kvm_get_vcpu_events(env);
if (ret < 0) {
return ret;
@@ -1878,3 +1977,14 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
return !(env->cr[0] & CR0_PE_MASK) ||
((env->segs[R_CS].selector & 3) != 3);
}
+
+void kvm_arch_init_irq_routing(KVMState *s)
+{
+ if (!kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+ /* If kernel can't do irq routing, interrupt source
+ * override 0->2 cannot be set up as required by HPET.
+ * So we have to disable it.
+ */
+ no_hpet = 1;
+ }
+}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index 2d67d1f4b8..fbcf4881a8 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -187,7 +187,10 @@ enum {
POWERPC_EXCP_EPERFM = 35, /* Embedded performance monitor interrupt */
POWERPC_EXCP_DOORI = 36, /* Embedded doorbell interrupt */
POWERPC_EXCP_DOORCI = 37, /* Embedded doorbell critical interrupt */
- /* Vectors 38 to 63 are reserved */
+ POWERPC_EXCP_GDOORI = 38, /* Embedded guest doorbell interrupt */
+ POWERPC_EXCP_GDOORCI = 39, /* Embedded guest doorbell critical interrupt*/
+ POWERPC_EXCP_HYPPRIV = 41, /* Embedded hypervisor priv instruction */
+ /* Vectors 42 to 63 are reserved */
/* Exceptions defined in the PowerPC server specification */
POWERPC_EXCP_RESET = 64, /* System reset exception */
POWERPC_EXCP_DSEG = 65, /* Data segment exception */
@@ -855,6 +858,22 @@ enum {
#define BOOKE206_MAX_TLBN 4
/*****************************************************************************/
+/* Embedded.Processor Control */
+
+#define DBELL_TYPE_SHIFT 27
+#define DBELL_TYPE_MASK (0x1f << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_DBELL (0x00 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_DBELL_CRIT (0x01 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL (0x02 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL_CRIT (0x03 << DBELL_TYPE_SHIFT)
+#define DBELL_TYPE_G_DBELL_MC (0x04 << DBELL_TYPE_SHIFT)
+
+#define DBELL_BRDCAST (1 << 26)
+#define DBELL_LPIDTAG_SHIFT 14
+#define DBELL_LPIDTAG_MASK (0xfff << DBELL_LPIDTAG_SHIFT)
+#define DBELL_PIRTAG_MASK 0x3fff
+
+/*****************************************************************************/
/* The whole PowerPC CPU context */
#define NB_MMU_MODES 3
@@ -1355,6 +1374,10 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
#define SPR_BOOKE_DVC2 (0x13F)
#define SPR_BOOKE_TSR (0x150)
#define SPR_BOOKE_TCR (0x154)
+#define SPR_BOOKE_TLB0PS (0x158)
+#define SPR_BOOKE_TLB1PS (0x159)
+#define SPR_BOOKE_TLB2PS (0x15A)
+#define SPR_BOOKE_TLB3PS (0x15B)
#define SPR_BOOKE_IVOR0 (0x190)
#define SPR_BOOKE_IVOR1 (0x191)
#define SPR_BOOKE_IVOR2 (0x192)
@@ -1371,6 +1394,11 @@ static inline void cpu_clone_regs(CPUState *env, target_ulong newsp)
#define SPR_BOOKE_IVOR13 (0x19D)
#define SPR_BOOKE_IVOR14 (0x19E)
#define SPR_BOOKE_IVOR15 (0x19F)
+#define SPR_BOOKE_IVOR38 (0x1B0)
+#define SPR_BOOKE_IVOR39 (0x1B1)
+#define SPR_BOOKE_IVOR40 (0x1B2)
+#define SPR_BOOKE_IVOR41 (0x1B3)
+#define SPR_BOOKE_IVOR42 (0x1B4)
#define SPR_BOOKE_SPEFSCR (0x200)
#define SPR_Exxx_BBEAR (0x201)
#define SPR_Exxx_BBTAR (0x202)
@@ -1888,8 +1916,10 @@ enum {
PPC2_VSX = 0x0000000000000002ULL,
/* Decimal Floating Point (DFP) */
PPC2_DFP = 0x0000000000000004ULL,
+ /* Embedded.Processor Control */
+ PPC2_PRCNTL = 0x0000000000000008ULL,
-#define PPC_TCG_INSNS2 (PPC2_BOOKE206)
+#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL)
};
/*****************************************************************************/
@@ -2103,6 +2133,10 @@ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn,
ea &= (1 << (tlb_bits - ways_bits)) - 1;
r = (ea << ways_bits) | way;
+ if (r >= booke206_tlb_size(env, tlbn)) {
+ return NULL;
+ }
+
/* bump up to tlbn index */
for (i = 0; i < tlbn; i++) {
r += booke206_tlb_size(env, i);
@@ -2111,6 +2145,27 @@ static inline ppcmas_tlb_t *booke206_get_tlbm(CPUState *env, const int tlbn,
return &env->tlb.tlbm[r];
}
+/* returns bitmap of supported page sizes for a given TLB */
+static inline uint32_t booke206_tlbnps(CPUState *env, const int tlbn)
+{
+ bool mav2 = false;
+ uint32_t ret = 0;
+
+ if (mav2) {
+ ret = env->spr[SPR_BOOKE_TLB0PS + tlbn];
+ } else {
+ uint32_t tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
+ uint32_t min = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+ uint32_t max = (tlbncfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT;
+ int i;
+ for (i = min; i <= max; i++) {
+ ret |= (1 << (i << 1));
+ }
+ }
+
+ return ret;
+}
+
#endif
extern void (*cpu_ppc_hypercall)(CPUState *);
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 58474536c0..e56fac8684 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1298,13 +1298,7 @@ target_phys_addr_t booke206_tlb_to_page_size(CPUState *env, ppcmas_tlb_t *tlb)
int tlbm_size;
tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
-
- if (tlbncfg & TLBnCFG_AVAIL) {
- tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
- } else {
- tlbm_size = (tlbncfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
- tlbm_size <<= 1;
- }
+ tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
return 1024ULL << tlbm_size;
}
@@ -1338,7 +1332,10 @@ int ppcmas_tlb_check(CPUState *env, ppcmas_tlb_t *tlb,
if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
return -1;
}
- *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+
+ if (raddrp) {
+ *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
+ }
return 0;
}
@@ -1445,6 +1442,9 @@ static int mmubooke206_get_physical_address(CPUState *env, mmu_ctx_t *ctx,
for (j = 0; j < ways; j++) {
tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
rw, access_type);
if (ret != -1) {
@@ -2698,22 +2698,10 @@ static inline void powerpc_excp(CPUState *env, int excp_model, int excp)
"Performance counter exception is not implemented yet !\n");
goto store_next;
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
- /* XXX: TODO */
- cpu_abort(env,
- "Embedded doorbell interrupt is not implemented yet !\n");
goto store_next;
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
- switch (excp_model) {
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- break;
- default:
- break;
- }
- /* XXX: TODO */
- cpu_abort(env, "Embedded doorbell critical interrupt "
- "is not implemented yet !\n");
+ srr0 = SPR_BOOKE_CSRR0;
+ srr1 = SPR_BOOKE_CSRR1;
goto store_next;
case POWERPC_EXCP_RESET: /* System reset exception */
if (msr_pow) {
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 470e42f676..148543a8a1 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -336,6 +336,9 @@ DEF_HELPER_0(booke206_tlbre, void)
DEF_HELPER_0(booke206_tlbwe, void)
DEF_HELPER_1(booke206_tlbsx, void, tl)
DEF_HELPER_1(booke206_tlbivax, void, tl)
+DEF_HELPER_1(booke206_tlbilx0, void, tl)
+DEF_HELPER_1(booke206_tlbilx1, void, tl)
+DEF_HELPER_1(booke206_tlbilx3, void, tl)
DEF_HELPER_1(booke206_tlbflush, void, i32)
DEF_HELPER_2(booke_setpid, void, i32, tl)
DEF_HELPER_1(6xx_tlbd, void, tl)
@@ -355,6 +358,8 @@ DEF_HELPER_FLAGS_1(load_sr, TCG_CALL_CONST, tl, tl);
DEF_HELPER_FLAGS_2(store_sr, TCG_CALL_CONST, void, tl, tl)
DEF_HELPER_FLAGS_1(602_mfrom, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl)
+DEF_HELPER_1(msgsnd, void, tl)
+DEF_HELPER_1(msgclr, void, tl)
#endif
DEF_HELPER_3(dlmzb, tl, tl, tl, i32)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index ce8ac5b4de..50cfa02f78 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -740,6 +740,7 @@ void kvmppc_set_papr(CPUState *env)
struct kvm_one_reg reg = {};
struct kvm_sregs sregs = {};
int ret;
+ uint64_t hior = env->spr[SPR_HIOR];
cap.cap = KVM_CAP_PPC_PAPR;
ret = kvm_vcpu_ioctl(env, KVM_ENABLE_CAP, &cap);
@@ -755,11 +756,14 @@ void kvmppc_set_papr(CPUState *env)
* Once we have qdev CPUs, move HIOR to a qdev property and
* remove this chunk.
*/
- reg.id = KVM_ONE_REG_PPC_HIOR;
- reg.u.reg64 = env->spr[SPR_HIOR];
+ reg.id = KVM_REG_PPC_HIOR;
+ reg.addr = (uintptr_t)&hior;
ret = kvm_vcpu_ioctl(env, KVM_SET_ONE_REG, &reg);
if (ret) {
- goto fail;
+ fprintf(stderr, "Couldn't set HIOR. Maybe you're running an old \n"
+ "kernel with support for HV KVM but no PAPR PR \n"
+ "KVM in which case things will work. If they don't \n"
+ "please update your host kernel!\n");
}
/* Set SDR1 so kernel space finds the HTAB */
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 6339c9559f..3f4e06789f 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -4228,6 +4228,7 @@ void helper_booke206_tlbwe(void)
{
uint32_t tlbncfg, tlbn;
ppcmas_tlb_t *tlb;
+ uint32_t size_tlb, size_ps;
switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
case MAS0_WQ_ALWAYS:
@@ -4259,12 +4260,37 @@ void helper_booke206_tlbwe(void)
tlb = booke206_cur_tlb(env);
+ if (!tlb) {
+ helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ }
+
+ /* check that we support the targeted size */
+ size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
+ size_ps = booke206_tlbnps(env, tlbn);
+ if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
+ !(size_ps & (1 << size_tlb))) {
+ helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_INVAL);
+ }
+
if (msr_gs) {
cpu_abort(env, "missing HV implementation\n");
}
tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
env->spr[SPR_BOOKE_MAS3];
tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
+
+ /* MAV 1.0 only */
+ if (!(tlbncfg & TLBnCFG_AVAIL)) {
+ /* force !AVAIL TLB entries to correct page size */
+ tlb->mas1 &= ~MAS1_TSIZE_MASK;
+ /* XXX can be configured in MMUCSR0 */
+ tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
+ }
+
/* XXX needs to change when supporting 64-bit e500 */
tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
@@ -4300,7 +4326,11 @@ void helper_booke206_tlbre(void)
ppcmas_tlb_t *tlb = NULL;
tlb = booke206_cur_tlb(env);
- booke206_tlb_to_mas(env, tlb);
+ if (!tlb) {
+ env->spr[SPR_BOOKE_MAS1] = 0;
+ } else {
+ booke206_tlb_to_mas(env, tlb);
+ }
}
void helper_booke206_tlbsx(target_ulong address)
@@ -4319,6 +4349,10 @@ void helper_booke206_tlbsx(target_ulong address)
for (j = 0; j < ways; j++) {
tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
+
if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
continue;
}
@@ -4362,6 +4396,9 @@ static inline void booke206_invalidate_ea_tlb(CPUState *env, int tlbn,
for (i = 0; i < ways; i++) {
ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
+ if (!tlb) {
+ continue;
+ }
mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
!(tlb->mas1 & MAS1_IPROT)) {
@@ -4395,6 +4432,73 @@ void helper_booke206_tlbivax(target_ulong address)
}
}
+void helper_booke206_tlbilx0(target_ulong address)
+{
+ /* XXX missing LPID handling */
+ booke206_flush_tlb(env, -1, 1);
+}
+
+void helper_booke206_tlbilx1(target_ulong address)
+{
+ int i, j;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ ppcmas_tlb_t *tlb = env->tlb.tlbm;
+ int tlb_size;
+
+ /* XXX missing LPID handling */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ tlb_size = booke206_tlb_size(env, i);
+ for (j = 0; j < tlb_size; j++) {
+ if (!(tlb[j].mas1 & MAS1_IPROT) &&
+ ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
+ tlb[j].mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb += booke206_tlb_size(env, i);
+ }
+ tlb_flush(env, 1);
+}
+
+void helper_booke206_tlbilx3(target_ulong address)
+{
+ int i, j;
+ ppcmas_tlb_t *tlb;
+ int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
+ int pid = tid >> MAS6_SPID_SHIFT;
+ int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
+ int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
+ /* XXX check for unsupported isize and raise an invalid opcode then */
+ int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
+ /* XXX implement MAV2 handling */
+ bool mav2 = false;
+
+ /* XXX missing LPID handling */
+ /* flush by pid and ea */
+ for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
+ int ways = booke206_tlb_ways(env, i);
+
+ for (j = 0; j < ways; j++) {
+ tlb = booke206_get_tlbm(env, i, address, j);
+ if (!tlb) {
+ continue;
+ }
+ if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
+ (tlb->mas1 & MAS1_IPROT) ||
+ ((tlb->mas1 & MAS1_IND) != ind) ||
+ ((tlb->mas8 & MAS8_TGS) != sgs)) {
+ continue;
+ }
+ if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
+ /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
+ continue;
+ }
+ /* XXX e500mc doesn't match SAS, but other cores might */
+ tlb->mas1 &= ~MAS1_VALID;
+ }
+ }
+ tlb_flush(env, 1);
+}
+
void helper_booke206_tlbflush(uint32_t type)
{
int flags = 0;
@@ -4410,4 +4514,57 @@ void helper_booke206_tlbflush(uint32_t type)
booke206_flush_tlb(env, flags, 1);
}
+/* Embedded.Processor Control */
+static int dbell2irq(target_ulong rb)
+{
+ int msg = rb & DBELL_TYPE_MASK;
+ int irq = -1;
+
+ switch (msg) {
+ case DBELL_TYPE_DBELL:
+ irq = PPC_INTERRUPT_DOORBELL;
+ break;
+ case DBELL_TYPE_DBELL_CRIT:
+ irq = PPC_INTERRUPT_CDOORBELL;
+ break;
+ case DBELL_TYPE_G_DBELL:
+ case DBELL_TYPE_G_DBELL_CRIT:
+ case DBELL_TYPE_G_DBELL_MC:
+ /* XXX implement */
+ default:
+ break;
+ }
+
+ return irq;
+}
+
+void helper_msgclr(target_ulong rb)
+{
+ int irq = dbell2irq(rb);
+
+ if (irq < 0) {
+ return;
+ }
+
+ env->pending_interrupts &= ~(1 << irq);
+}
+
+void helper_msgsnd(target_ulong rb)
+{
+ int irq = dbell2irq(rb);
+ int pir = rb & DBELL_PIRTAG_MASK;
+ CPUState *cenv;
+
+ if (irq < 0) {
+ return;
+ }
+
+ for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
+ if ((rb & DBELL_BRDCAST) || (cenv->spr[SPR_BOOKE_PIR] == pir)) {
+ cenv->pending_interrupts |= 1 << irq;
+ cpu_interrupt(cenv, CPU_INTERRUPT_HARD);
+ }
+ }
+}
+
#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 66eae30209..b2780dbe55 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6088,6 +6088,7 @@ static void gen_tlbwe_booke206(DisasContext *ctx)
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
+ gen_update_nip(ctx, ctx->nip - 4);
gen_helper_booke206_tlbwe();
#endif
}
@@ -6110,6 +6111,39 @@ static void gen_tlbivax_booke206(DisasContext *ctx)
#endif
}
+static void gen_tlbilx_booke206(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+ TCGv t0;
+ if (unlikely(!ctx->mem_idx)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ return;
+ }
+
+ t0 = tcg_temp_new();
+ gen_addr_reg_index(ctx, t0);
+
+ switch((ctx->opcode >> 21) & 0x3) {
+ case 0:
+ gen_helper_booke206_tlbilx0(t0);
+ break;
+ case 1:
+ gen_helper_booke206_tlbilx1(t0);
+ break;
+ case 3:
+ gen_helper_booke206_tlbilx3(t0);
+ break;
+ default:
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+ break;
+ }
+
+ tcg_temp_free(t0);
+#endif
+}
+
/* wrtee */
static void gen_wrtee(DisasContext *ctx)
@@ -6172,7 +6206,7 @@ static void gen_mbar(DisasContext *ctx)
}
/* msync replaces sync on 440 */
-static void gen_msync(DisasContext *ctx)
+static void gen_msync_4xx(DisasContext *ctx)
{
/* interpreted as no-op */
}
@@ -6186,6 +6220,36 @@ static void gen_icbt_440(DisasContext *ctx)
*/
}
+/* Embedded.Processor Control */
+
+static void gen_msgclr(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+ if (unlikely(ctx->mem_idx == 0)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ return;
+ }
+
+ gen_helper_msgclr(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
+static void gen_msgsnd(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+#else
+ if (unlikely(ctx->mem_idx == 0)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
+ return;
+ }
+
+ gen_helper_msgsnd(cpu_gpr[rB(ctx->opcode)]);
+#endif
+}
+
/*** Altivec vector extension ***/
/* Altivec registers moves */
@@ -8574,13 +8638,18 @@ GEN_HANDLER2_E(tlbwe_booke206, "tlbwe", 0x1F, 0x12, 0x1E, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
GEN_HANDLER2_E(tlbivax_booke206, "tlbivax", 0x1F, 0x12, 0x18, 0x00000001,
PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(tlbilx_booke206, "tlbilx", 0x1F, 0x12, 0x00, 0x03800001,
+ PPC_NONE, PPC2_BOOKE206),
+GEN_HANDLER2_E(msgsnd, "msgsnd", 0x1F, 0x0E, 0x06, 0x03ff0001,
+ PPC_NONE, PPC2_PRCNTL),
+GEN_HANDLER2_E(msgclr, "msgclr", 0x1F, 0x0E, 0x07, 0x03ff0001,
+ PPC_NONE, PPC2_PRCNTL),
GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_WRTEE),
GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000E7C01, PPC_WRTEE),
GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC),
GEN_HANDLER_E(mbar, 0x1F, 0x16, 0x1a, 0x001FF801,
PPC_BOOKE, PPC2_BOOKE206),
-GEN_HANDLER_E(msync, 0x1F, 0x16, 0x12, 0x03FFF801,
- PPC_BOOKE, PPC2_BOOKE206),
+GEN_HANDLER(msync_4xx, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE),
GEN_HANDLER2_E(icbt_440, "icbt", 0x1F, 0x16, 0x00, 0x03E00001,
PPC_BOOKE, PPC2_BOOKE206),
GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 47d73a6bf9..6253076f68 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -526,26 +526,27 @@ static void spr_write_excp_prefix (void *opaque, int sprn, int gprn)
static void spr_write_excp_vector (void *opaque, int sprn, int gprn)
{
DisasContext *ctx = opaque;
+ int sprn_offs;
if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
- TCGv t0 = tcg_temp_new();
- tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
- tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR0]));
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
+ sprn_offs = sprn - SPR_BOOKE_IVOR0;
} else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
- TCGv t0 = tcg_temp_new();
- tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
- tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
- tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn - SPR_BOOKE_IVOR32 + 32]));
- gen_store_spr(sprn, t0);
- tcg_temp_free(t0);
+ sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32;
+ } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
+ sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
} else {
printf("Trying to write an unknown exception vector %d %03x\n",
sprn, sprn);
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
+ return;
}
+
+ TCGv t0 = tcg_temp_new();
+ tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUState, ivor_mask));
+ tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
+ tcg_gen_st_tl(t0, cpu_env, offsetof(CPUState, excp_vectors[sprn_offs]));
+ gen_store_spr(sprn, t0);
+ tcg_temp_free(t0);
}
#endif
@@ -1434,8 +1435,8 @@ static void gen_spr_BookE (CPUPPCState *env, uint64_t ivor_mask)
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVOR32, SPR_BOOKE_IVOR33, SPR_BOOKE_IVOR34, SPR_BOOKE_IVOR35,
- SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
- SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
+ SPR_BOOKE_IVOR36, SPR_BOOKE_IVOR37, SPR_BOOKE_IVOR38, SPR_BOOKE_IVOR39,
+ SPR_BOOKE_IVOR40, SPR_BOOKE_IVOR41, SPR_BOOKE_IVOR42, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx, SPR_BOOKE_IVORxx,
@@ -3516,6 +3517,9 @@ static void init_proc_405 (CPUPPCState *env)
/* PowerPC 440 EP */
#define POWERPC_INSNS_440EP (PPC_INSNS_BASE | PPC_STRING | \
+ PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | \
+ PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | \
+ PPC_FLOAT_STFIWX | \
PPC_DCR | PPC_WRTEE | PPC_RFMCI | \
PPC_CACHE | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
@@ -3523,7 +3527,7 @@ static void init_proc_405 (CPUPPCState *env)
PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | \
PPC_440_SPEC)
#define POWERPC_INSNS2_440EP (PPC_NONE)
-#define POWERPC_MSRM_440EP (0x000000000006D630ULL)
+#define POWERPC_MSRM_440EP (0x000000000006FF30ULL)
#define POWERPC_MMU_440EP (POWERPC_MMU_BOOKE)
#define POWERPC_EXCP_440EP (POWERPC_EXCP_BOOKE)
#define POWERPC_INPUT_440EP (PPC_FLAGS_INPUT_BookE)
@@ -3532,7 +3536,6 @@ static void init_proc_405 (CPUPPCState *env)
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK)
#define check_pow_440EP check_pow_nocheck
-__attribute__ (( unused ))
static void init_proc_440EP (CPUPPCState *env)
{
/* Time base */
@@ -3593,7 +3596,7 @@ static void init_proc_440EP (CPUPPCState *env)
init_excp_BookE(env);
env->dcache_line_size = 32;
env->icache_line_size = 32;
- /* XXX: TODO: allocate internal IRQ controller */
+ ppc40x_irq_init(env);
SET_FIT_PERIOD(12, 16, 20, 24);
SET_WDT_PERIOD(20, 24, 28, 32);
@@ -4368,7 +4371,7 @@ static void init_proc_e300 (CPUPPCState *env)
PPC_WRTEE | PPC_RFDI | \
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
- PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
#define POWERPC_INSNS2_e500v1 (PPC2_BOOKE206)
#define POWERPC_MSRM_e500v1 (0x000000000606FF30ULL)
#define POWERPC_MMU_e500v1 (POWERPC_MMU_BOOKE206)
@@ -4387,7 +4390,7 @@ static void init_proc_e300 (CPUPPCState *env)
PPC_WRTEE | PPC_RFDI | \
PPC_CACHE | PPC_CACHE_LOCK | PPC_CACHE_ICBI | \
PPC_CACHE_DCBZ | PPC_CACHE_DCBA | \
- PPC_MEM_TLBSYNC | PPC_TLBIVAX)
+ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
#define POWERPC_INSNS2_e500v2 (PPC2_BOOKE206)
#define POWERPC_MSRM_e500v2 (0x000000000606FF30ULL)
#define POWERPC_MMU_e500v2 (POWERPC_MMU_BOOKE206)
@@ -4408,8 +4411,8 @@ static void init_proc_e300 (CPUPPCState *env)
PPC_FLOAT | PPC_FLOAT_FRES | \
PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL | \
PPC_FLOAT_STFIWX | PPC_WAIT | \
- PPC_MEM_TLBSYNC | PPC_TLBIVAX)
-#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206)
+ PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC)
+#define POWERPC_INSNS2_e500mc (PPC2_BOOKE206 | PPC2_PRCNTL)
#define POWERPC_MSRM_e500mc (0x000000001402FB36ULL)
#define POWERPC_MMU_e500mc (POWERPC_MMU_BOOKE206)
#define POWERPC_EXCP_e500mc (POWERPC_EXCP_BOOKE)
@@ -4430,6 +4433,9 @@ enum fsl_e500_version {
static void init_proc_e500 (CPUPPCState *env, int version)
{
uint32_t tlbncfg[2];
+ uint64_t ivor_mask = 0x0000000F0000FFFFULL;
+ uint32_t l1cfg0 = 0x3800 /* 8 ways */
+ | 0x0020; /* 32 kb */
#if !defined(CONFIG_USER_ONLY)
int i;
#endif
@@ -4441,7 +4447,10 @@ static void init_proc_e500 (CPUPPCState *env, int version)
* complain when accessing them.
* gen_spr_BookE(env, 0x0000000F0000FD7FULL);
*/
- gen_spr_BookE(env, 0x0000000F0000FFFFULL);
+ if (version == fsl_e500mc) {
+ ivor_mask = 0x000003FE0000FFFFULL;
+ }
+ gen_spr_BookE(env, ivor_mask);
/* Processor identification */
spr_register(env, SPR_BOOKE_PIR, "PIR",
SPR_NOACCESS, SPR_NOACCESS,
@@ -4478,6 +4487,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
tlbncfg[1] = gen_tlbncfg(64, 1, 12, TLBnCFG_AVAIL | TLBnCFG_IPROT, 64);
env->dcache_line_size = 64;
env->icache_line_size = 64;
+ l1cfg0 |= 0x1000000; /* 64 byte cache block size */
break;
default:
cpu_abort(env, "Unknown CPU: " TARGET_FMT_lx "\n", env->spr[SPR_PVR]);
@@ -4528,7 +4538,7 @@ static void init_proc_e500 (CPUPPCState *env, int version)
spr_register(env, SPR_Exxx_L1CFG0, "L1CFG0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
- 0x00000000);
+ l1cfg0);
/* XXX : not implemented */
spr_register(env, SPR_Exxx_L1CSR0, "L1CSR0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -7869,22 +7879,14 @@ static const ppc_def_t ppc_defs[] = {
POWERPC_DEF("440H6", CPU_POWERPC_440H6, 440Gx5),
#endif
/* PowerPC 440 microcontrolers */
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EP */
POWERPC_DEF("440EP", CPU_POWERPC_440EP, 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EPa */
POWERPC_DEF("440EPa", CPU_POWERPC_440EPa, 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EPb */
POWERPC_DEF("440EPb", CPU_POWERPC_440EPb, 440EP),
-#endif
-#if defined(TODO_USER_ONLY)
/* PowerPC 440 EPX */
POWERPC_DEF("440EPX", CPU_POWERPC_440EPX, 440EP),
-#endif
#if defined(TODO_USER_ONLY)
/* PowerPC 440 GP */
POWERPC_DEF("440GP", CPU_POWERPC_440GP, 440GP),
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index a992c293af..9d2edb09bd 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -459,7 +459,7 @@ uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
return ret;
}
-uint64 helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
+uint64_t helper_bshuffle(uint64_t gsr, uint64_t src1, uint64_t src2)
{
union {
uint64_t ll[2];
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
index 1f3ab031f7..926db5cb91 100644
--- a/test-qmp-input-visitor.c
+++ b/test-qmp-input-visitor.c
@@ -38,8 +38,9 @@ static void visitor_input_teardown(TestInputVisitorData *data,
/* This is provided instead of a test setup function so that the JSON
string used by the tests are kept in the test functions (and not
int main()) */
-static Visitor *visitor_input_test_init(TestInputVisitorData *data,
- const char *json_string, ...)
+static GCC_FMT_ATTR(2, 3)
+Visitor *visitor_input_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
{
Visitor *v;
va_list ap;
@@ -66,7 +67,7 @@ static void test_visitor_in_int(TestInputVisitorData *data,
Error *errp = NULL;
Visitor *v;
- v = visitor_input_test_init(data, "%d", value);
+ v = visitor_input_test_init(data, "%" PRId64, value);
visit_type_int(v, &res, NULL, &errp);
g_assert(!error_is_set(&errp));
diff --git a/tests/Makefile b/tests/Makefile
index efde63a5f3..55e8eb0ad5 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -36,4 +36,4 @@ test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-ob
.PHONY: check
check: $(CHECKS)
- gtester $(CHECKS)
+ $(call quiet-command, gtester $(CHECKS), " CHECK")
diff --git a/trace-events b/trace-events
index c18435bbe1..5d05749643 100644
--- a/trace-events
+++ b/trace-events
@@ -65,14 +65,25 @@ bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %
bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
bdrv_co_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
+bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
bdrv_co_writev(void *bs, int64_t sector_num, int nb_sector) "bs %p sector_num %"PRId64" nb_sectors %d"
bdrv_co_io_em(void *bs, int64_t sector_num, int nb_sectors, int is_write, void *acb) "bs %p sector_num %"PRId64" nb_sectors %d is_write %d acb %p"
-bdrv_co_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
+bdrv_co_do_copy_on_readv(void *bs, int64_t sector_num, int nb_sectors, int64_t cluster_sector_num, int cluster_nb_sectors) "bs %p sector_num %"PRId64" nb_sectors %d cluster_sector_num %"PRId64" cluster_nb_sectors %d"
+
+# block/stream.c
+stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
+stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
+
+# blockdev.c
+qmp_block_job_cancel(void *job) "job %p"
+block_stream_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
+qmp_block_stream(void *bs, void *job) "bs %p job %p"
# hw/virtio-blk.c
virtio_blk_req_complete(void *req, int status) "req %p status %d"
virtio_blk_rw_complete(void *req, int ret) "req %p ret %d"
virtio_blk_handle_write(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
+virtio_blk_handle_read(void *req, uint64_t sector, size_t nsectors) "req %p sector %"PRIu64" nsectors %zu"
# posix-aio-compat.c
paio_submit(void *acb, void *opaque, int64_t sector_num, int nb_sectors, int type) "acb %p opaque %p sector_num %"PRId64" nb_sectors %d type %d"
@@ -95,9 +106,9 @@ cpu_get_apic_base(uint64_t val) "%016"PRIx64
apic_mem_readl(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
# coalescing
+apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d"
apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
-apic_set_irq(int apic_irq_delivered) "coalescing %d"
# hw/cs4231.c
cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
@@ -246,6 +257,7 @@ usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query
usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d"
usb_set_addr(int addr) "dev %d"
usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d"
+usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d"
usb_clear_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
usb_set_device_feature(int addr, int feature, int ret) "dev %d, feature %d, ret %d"
@@ -339,6 +351,7 @@ grlib_irqmp_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" valu
# hw/grlib_apbuart.c
grlib_apbuart_event(int event) "event:%d"
grlib_apbuart_writel_unknown(uint64_t addr, uint32_t value) "addr 0x%"PRIx64" value 0x%x"
+grlib_apbuart_readl_unknown(uint64_t addr) "addr 0x%"PRIx64""
# hw/leon3.c
leon3_set_irq(int intno) "Set CPU IRQ %d"
diff --git a/ui/sdl.c b/ui/sdl.c
index 8cafc44e71..6f8091c725 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -461,18 +461,23 @@ static void sdl_show_cursor(void)
static void sdl_grab_start(void)
{
+ /*
+ * If the application is not active, do not try to enter grab state. This
+ * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
+ * application (SDL bug).
+ */
+ if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) {
+ return;
+ }
if (guest_cursor) {
SDL_SetCursor(guest_sprite);
if (!kbd_mouse_is_absolute() && !absolute_enabled)
SDL_WarpMouse(guest_x, guest_y);
} else
sdl_hide_cursor();
-
- if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
- gui_grab = 1;
- sdl_update_caption();
- } else
- sdl_show_cursor();
+ SDL_WM_GrabInput(SDL_GRAB_ON);
+ gui_grab = 1;
+ sdl_update_caption();
}
static void sdl_grab_end(void)
@@ -483,12 +488,25 @@ static void sdl_grab_end(void)
sdl_update_caption();
}
+static void absolute_mouse_grab(void)
+{
+ int mouse_x, mouse_y;
+
+ SDL_GetMouseState(&mouse_x, &mouse_y);
+ if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
+ mouse_y > 0 && mouse_y < real_screen->h - 1) {
+ sdl_grab_start();
+ }
+}
+
static void sdl_mouse_mode_change(Notifier *notify, void *data)
{
if (kbd_mouse_is_absolute()) {
if (!absolute_enabled) {
- sdl_grab_start();
absolute_enabled = 1;
+ if (is_graphic_console()) {
+ absolute_mouse_grab();
+ }
}
} else if (absolute_enabled) {
if (!gui_fullscreen) {
@@ -571,19 +589,6 @@ static void toggle_full_screen(DisplayState *ds)
vga_hw_update();
}
-static void absolute_mouse_grab(void)
-{
- int mouse_x, mouse_y;
-
- if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
- SDL_GetMouseState(&mouse_x, &mouse_y);
- if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
- mouse_y > 0 && mouse_y < real_screen->h - 1) {
- sdl_grab_start();
- }
- }
-}
-
static void handle_keydown(DisplayState *ds, SDL_Event *ev)
{
int mod_state;
@@ -743,11 +748,7 @@ static void handle_keyup(DisplayState *ds, SDL_Event *ev)
if (gui_keysym == 0) {
/* exit/enter grab if pressing Ctrl-Alt */
if (!gui_grab) {
- /* If the application is not active, do not try to enter grab
- * state. It prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from
- * blocking all the application (SDL bug). */
- if (is_graphic_console() &&
- SDL_GetAppState() & SDL_APPACTIVE) {
+ if (is_graphic_console()) {
sdl_grab_start();
}
} else if (!gui_fullscreen) {
@@ -777,7 +778,7 @@ static void handle_mousemotion(DisplayState *ds, SDL_Event *ev)
ev->motion.x == max_x || ev->motion.y == max_y)) {
sdl_grab_end();
}
- if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
+ if (!gui_grab &&
(ev->motion.x > 0 && ev->motion.x < max_x &&
ev->motion.y > 0 && ev->motion.y < max_y)) {
sdl_grab_start();
@@ -801,8 +802,7 @@ static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
bev = &ev->button;
if (!gui_grab && !kbd_mouse_is_absolute()) {
- if (ev->type == SDL_MOUSEBUTTONDOWN &&
- (bev->button == SDL_BUTTON_LEFT)) {
+ if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
/* start grabbing all events */
sdl_grab_start();
}
@@ -828,10 +828,14 @@ static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
static void handle_activation(DisplayState *ds, SDL_Event *ev)
{
+#ifdef _WIN32
+ /* Disable grab if the window no longer has the focus
+ * (Windows-only workaround) */
if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
!ev->active.gain && !gui_fullscreen) {
sdl_grab_end();
}
+#endif
if (!gui_grab && ev->active.gain && is_graphic_console() &&
(kbd_mouse_is_absolute() || absolute_enabled)) {
absolute_mouse_grab();
diff --git a/ui/vnc.c b/ui/vnc.c
index 1869a7adea..16b79ec423 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2686,19 +2686,16 @@ int vnc_display_disable_login(DisplayState *ds)
int vnc_display_password(DisplayState *ds, const char *password)
{
- int ret = 0;
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
if (!vs) {
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (!password) {
/* This is not the intention of this interface but err on the side
of being safe */
- ret = vnc_display_disable_login(ds);
- goto out;
+ return vnc_display_disable_login(ds);
}
if (vs->password) {
@@ -2707,11 +2704,8 @@ int vnc_display_password(DisplayState *ds, const char *password)
}
vs->password = g_strdup(password);
vs->auth = VNC_AUTH_VNC;
-out:
- if (ret != 0) {
- qerror_report(QERR_SET_PASSWD_FAILED);
- }
- return ret;
+
+ return 0;
}
int vnc_display_pw_expire(DisplayState *ds, time_t expires)
diff --git a/usb-bsd.c b/usb-bsd.c
index 11875527d5..fc722b3cfa 100644
--- a/usb-bsd.c
+++ b/usb-bsd.c
@@ -397,21 +397,29 @@ fail:
return ret;
}
-static struct USBDeviceInfo usb_host_dev_info = {
- .product_desc = "USB Host Device",
- .qdev.name = "usb-host",
- .qdev.size = sizeof(USBHostDevice),
- .init = usb_host_initfn,
- .handle_packet = usb_generic_handle_packet,
- .handle_reset = usb_host_handle_reset,
- .handle_control = usb_host_handle_control,
- .handle_data = usb_host_handle_data,
- .handle_destroy = usb_host_handle_destroy,
+static void usb_host_class_initfn(ObjectClass *klass, void *data)
+{
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->product_desc = "USB Host Device";
+ uc->init = usb_host_initfn;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->handle_reset = usb_host_handle_reset;
+ uc->handle_control = usb_host_handle_control;
+ uc->handle_data = usb_host_handle_data;
+ uc->handle_destroy = usb_host_handle_destroy;
+}
+
+static TypeInfo usb_host_dev_info = {
+ .name = "usb-host",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHostDevice),
+ .class_init = usb_host_class_initfn,
};
static void usb_host_register_devices(void)
{
- usb_qdev_register(&usb_host_dev_info);
+ type_register_static(&usb_host_dev_info);
}
device_init(usb_host_register_devices)
diff --git a/usb-linux.c b/usb-linux.c
index 749ce71081..e7fc9ecd5c 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -66,27 +66,11 @@ typedef int USBScanFunc(void *opaque, int bus_num, int addr, const char *port,
#define DPRINTF(...)
#endif
-#define USBDBG_DEVOPENED "husb: opened %s/devices\n"
-
-#define USBPROCBUS_PATH "/proc/bus/usb"
#define PRODUCT_NAME_SZ 32
-#define MAX_ENDPOINTS 15
#define MAX_PORTLEN 16
-#define USBDEVBUS_PATH "/dev/bus/usb"
-#define USBSYSBUS_PATH "/sys/bus/usb"
-
-static char *usb_host_device_path;
-
-#define USB_FS_NONE 0
-#define USB_FS_PROC 1
-#define USB_FS_DEV 2
-#define USB_FS_SYS 3
-
-static int usb_fs_type;
/* endpoint association data */
#define ISO_FRAME_DESC_PER_URB 32
-#define INVALID_EP_TYPE 255
/* devio.c limits single requests to 16k */
#define MAX_USBFS_BUFFER_SIZE 16384
@@ -94,13 +78,11 @@ static int usb_fs_type;
typedef struct AsyncURB AsyncURB;
struct endp_data {
- uint8_t type;
uint8_t halted;
uint8_t iso_started;
AsyncURB *iso_urb;
int iso_urb_idx;
int iso_buffer_used;
- int max_packet_size;
int inflight;
};
@@ -120,14 +102,12 @@ typedef struct USBHostDevice {
uint8_t descr[8192];
int descr_len;
- int configuration;
- int ninterfaces;
int closing;
uint32_t iso_urb_count;
Notifier exit;
- struct endp_data ep_in[MAX_ENDPOINTS];
- struct endp_data ep_out[MAX_ENDPOINTS];
+ struct endp_data ep_in[USB_MAX_ENDPOINTS];
+ struct endp_data ep_out[USB_MAX_ENDPOINTS];
QLIST_HEAD(, AsyncURB) aurbs;
/* Host side address */
@@ -149,6 +129,19 @@ static int usb_host_read_file(char *line, size_t line_size,
const char *device_file, const char *device_name);
static int usb_linux_update_endp_table(USBHostDevice *s);
+static int usb_host_usbfs_type(USBHostDevice *s, USBPacket *p)
+{
+ static const int usbfs[] = {
+ [USB_ENDPOINT_XFER_CONTROL] = USBDEVFS_URB_TYPE_CONTROL,
+ [USB_ENDPOINT_XFER_ISOC] = USBDEVFS_URB_TYPE_ISO,
+ [USB_ENDPOINT_XFER_BULK] = USBDEVFS_URB_TYPE_BULK,
+ [USB_ENDPOINT_XFER_INT] = USBDEVFS_URB_TYPE_INTERRUPT,
+ };
+ uint8_t type = usb_ep_get_type(&s->dev, p->pid, p->devep);
+ assert(type < ARRAY_SIZE(usbfs));
+ return usbfs[type];
+}
+
static int usb_host_do_reset(USBHostDevice *dev)
{
struct timeval s, e;
@@ -172,18 +165,18 @@ static struct endp_data *get_endp(USBHostDevice *s, int pid, int ep)
{
struct endp_data *eps = pid == USB_TOKEN_IN ? s->ep_in : s->ep_out;
assert(pid == USB_TOKEN_IN || pid == USB_TOKEN_OUT);
- assert(ep > 0 && ep <= MAX_ENDPOINTS);
+ assert(ep > 0 && ep <= USB_MAX_ENDPOINTS);
return eps + ep - 1;
}
static int is_isoc(USBHostDevice *s, int pid, int ep)
{
- return get_endp(s, pid, ep)->type == USBDEVFS_URB_TYPE_ISO;
+ return usb_ep_get_type(&s->dev, pid, ep) == USB_ENDPOINT_XFER_ISOC;
}
static int is_valid(USBHostDevice *s, int pid, int ep)
{
- return get_endp(s, pid, ep)->type != INVALID_EP_TYPE;
+ return usb_ep_get_type(&s->dev, pid, ep) != USB_ENDPOINT_XFER_INVALID;
}
static int is_halted(USBHostDevice *s, int pid, int ep)
@@ -265,26 +258,6 @@ static int get_iso_buffer_used(USBHostDevice *s, int pid, int ep)
return get_endp(s, pid, ep)->iso_buffer_used;
}
-static void set_max_packet_size(USBHostDevice *s, int pid, int ep,
- uint8_t *descriptor)
-{
- int raw = descriptor[4] + (descriptor[5] << 8);
- int size, microframes;
-
- size = raw & 0x7ff;
- switch ((raw >> 11) & 3) {
- case 1: microframes = 2; break;
- case 2: microframes = 3; break;
- default: microframes = 1; break;
- }
- get_endp(s, pid, ep)->max_packet_size = size * microframes;
-}
-
-static int get_max_packet_size(USBHostDevice *s, int pid, int ep)
-{
- return get_endp(s, pid, ep)->max_packet_size;
-}
-
/*
* Async URB state.
* We always allocate iso packet descriptors even for bulk transfers
@@ -431,6 +404,31 @@ static void usb_host_async_cancel(USBDevice *dev, USBPacket *p)
}
}
+static int usb_host_open_device(int bus, int addr)
+{
+ const char *usbfs = NULL;
+ char filename[32];
+ struct stat st;
+ int fd, rc;
+
+ rc = stat("/dev/bus/usb", &st);
+ if (rc == 0 && S_ISDIR(st.st_mode)) {
+ /* udev-created device nodes available */
+ usbfs = "/dev/bus/usb";
+ } else {
+ /* fallback: usbfs mounted below /proc */
+ usbfs = "/proc/bus/usb";
+ }
+
+ snprintf(filename, sizeof(filename), "%s/%03d/%03d",
+ usbfs, bus, addr);
+ fd = open(filename, O_RDWR | O_NONBLOCK);
+ if (fd < 0) {
+ fprintf(stderr, "husb: open %s: %s\n", filename, strerror(errno));
+ }
+ return fd;
+}
+
static int usb_host_claim_port(USBHostDevice *s)
{
#ifdef USBDEVFS_CLAIM_PORT
@@ -460,12 +458,7 @@ static int usb_host_claim_port(USBHostDevice *s)
return -1;
}
- if (!usb_host_device_path) {
- return -1;
- }
- snprintf(line, sizeof(line), "%s/%03d/%03d",
- usb_host_device_path, s->match.bus_num, hub_addr);
- s->hub_fd = open(line, O_RDWR | O_NONBLOCK);
+ s->hub_fd = usb_host_open_device(s->match.bus_num, hub_addr);
if (s->hub_fd < 0) {
return -1;
}
@@ -522,10 +515,6 @@ static int usb_linux_get_num_interfaces(USBHostDevice *s)
char device_name[64], line[1024];
int num_interfaces = 0;
- if (usb_fs_type != USB_FS_SYS) {
- return -1;
- }
-
sprintf(device_name, "%d-%s", s->bus_num, s->port);
if (!usb_host_read_file(line, sizeof(line), "bNumInterfaces",
device_name)) {
@@ -544,9 +533,13 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
int interface, nb_interfaces;
int ret, i;
+ for (i = 0; i < USB_MAX_INTERFACES; i++) {
+ dev->dev.altsetting[i] = 0;
+ }
+
if (configuration == 0) { /* address state - ignore */
- dev->ninterfaces = 0;
- dev->configuration = 0;
+ dev->dev.ninterfaces = 0;
+ dev->dev.configuration = 0;
return 1;
}
@@ -604,8 +597,8 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration)
trace_usb_host_claim_interfaces(dev->bus_num, dev->addr,
nb_interfaces, configuration);
- dev->ninterfaces = nb_interfaces;
- dev->configuration = configuration;
+ dev->dev.ninterfaces = nb_interfaces;
+ dev->dev.configuration = configuration;
return 1;
fail:
@@ -622,7 +615,7 @@ static int usb_host_release_interfaces(USBHostDevice *s)
trace_usb_host_release_interfaces(s->bus_num, s->addr);
- for (i = 0; i < s->ninterfaces; i++) {
+ for (i = 0; i < s->dev.ninterfaces; i++) {
ret = ioctl(s->fd, USBDEVFS_RELEASEINTERFACE, &i);
if (ret < 0) {
perror("USBDEVFS_RELEASEINTERFACE");
@@ -660,7 +653,7 @@ static void usb_host_handle_destroy(USBDevice *dev)
static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, int pid, uint8_t ep)
{
AsyncURB *aurb;
- int i, j, len = get_max_packet_size(s, pid, ep);
+ int i, j, len = usb_ep_get_max_packet_size(&s->dev, pid, ep);
aurb = g_malloc0(s->iso_urb_count * sizeof(*aurb));
for (i = 0; i < s->iso_urb_count; i++) {
@@ -740,7 +733,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in)
int i, j, ret, max_packet_size, offset, len = 0;
uint8_t *buf;
- max_packet_size = get_max_packet_size(s, p->pid, p->devep);
+ max_packet_size = usb_ep_get_max_packet_size(&s->dev, p->pid, p->devep);
if (max_packet_size == 0)
return USB_RET_NAK;
@@ -892,7 +885,7 @@ static int usb_host_handle_data(USBDevice *dev, USBPacket *p)
urb = &aurb->urb;
urb->endpoint = ep;
- urb->type = USBDEVFS_URB_TYPE_BULK;
+ urb->type = usb_host_usbfs_type(s, p);
urb->usercontext = s;
urb->buffer = pbuf;
urb->buffer_length = prem;
@@ -988,7 +981,7 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
trace_usb_host_set_interface(s->bus_num, s->addr, iface, alt);
- for (i = 1; i <= MAX_ENDPOINTS; i++) {
+ for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
if (is_isoc(s, USB_TOKEN_IN, i)) {
usb_host_stop_n_free_iso(s, USB_TOKEN_IN, i);
}
@@ -997,6 +990,10 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
}
}
+ if (iface >= USB_MAX_INTERFACES) {
+ return USB_RET_STALL;
+ }
+
si.interface = iface;
si.altsetting = alt;
ret = ioctl(s->fd, USBDEVFS_SETINTERFACE, &si);
@@ -1007,6 +1004,8 @@ static int usb_host_set_interface(USBHostDevice *s, int iface, int alt)
if (ret < 0) {
return ctrl_error();
}
+
+ s->dev.altsetting[iface] = alt;
usb_linux_update_endp_table(s);
return 0;
}
@@ -1090,41 +1089,21 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
static uint8_t usb_linux_get_alt_setting(USBHostDevice *s,
uint8_t configuration, uint8_t interface)
{
- uint8_t alt_setting;
- struct usb_ctrltransfer ct;
- int ret;
-
- if (usb_fs_type == USB_FS_SYS) {
- char device_name[64], line[1024];
- int alt_setting;
+ char device_name[64], line[1024];
+ int alt_setting;
- sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
- (int)configuration, (int)interface);
+ sprintf(device_name, "%d-%s:%d.%d", s->bus_num, s->port,
+ (int)configuration, (int)interface);
- if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
- device_name)) {
- goto usbdevfs;
- }
- if (sscanf(line, "%d", &alt_setting) != 1) {
- goto usbdevfs;
- }
- return alt_setting;
- }
-
-usbdevfs:
- ct.bRequestType = USB_DIR_IN | USB_RECIP_INTERFACE;
- ct.bRequest = USB_REQ_GET_INTERFACE;
- ct.wValue = 0;
- ct.wIndex = interface;
- ct.wLength = 1;
- ct.data = &alt_setting;
- ct.timeout = 50;
- ret = ioctl(s->fd, USBDEVFS_CONTROL, &ct);
- if (ret < 0) {
+ if (!usb_host_read_file(line, sizeof(line), "bAlternateSetting",
+ device_name)) {
+ /* Assume alt 0 on error */
+ return 0;
+ }
+ if (sscanf(line, "%d", &alt_setting) != 1) {
/* Assume alt 0 on error */
return 0;
}
-
return alt_setting;
}
@@ -1133,15 +1112,13 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
{
uint8_t *descriptors;
uint8_t devep, type, alt_interface;
+ uint16_t raw;
int interface, length, i, ep, pid;
struct endp_data *epd;
- for (i = 0; i < MAX_ENDPOINTS; i++) {
- s->ep_in[i].type = INVALID_EP_TYPE;
- s->ep_out[i].type = INVALID_EP_TYPE;
- }
+ usb_ep_init(&s->dev);
- if (s->configuration == 0) {
+ if (s->dev.configuration == 0) {
/* not configured yet -- leave all endpoints disabled */
return 0;
}
@@ -1156,12 +1133,11 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
if (descriptors[i + 1] != USB_DT_CONFIG) {
fprintf(stderr, "invalid descriptor data\n");
return 1;
- } else if (descriptors[i + 5] != s->configuration) {
- DPRINTF("not requested configuration %d\n", s->configuration);
+ } else if (descriptors[i + 5] != s->dev.configuration) {
+ DPRINTF("not requested configuration %d\n", s->dev.configuration);
i += (descriptors[i + 3] << 8) + descriptors[i + 2];
continue;
}
-
i += descriptors[i];
if (descriptors[i + 1] != USB_DT_INTERFACE ||
@@ -1172,7 +1148,7 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
}
interface = descriptors[i + 2];
- alt_interface = usb_linux_get_alt_setting(s, s->configuration,
+ alt_interface = usb_linux_get_alt_setting(s, s->dev.configuration,
interface);
/* the current interface descriptor is the active interface
@@ -1203,32 +1179,23 @@ static int usb_linux_update_endp_table(USBHostDevice *s)
return 1;
}
- switch (descriptors[i + 3] & 0x3) {
- case 0x00:
- type = USBDEVFS_URB_TYPE_CONTROL;
- break;
- case 0x01:
- type = USBDEVFS_URB_TYPE_ISO;
- set_max_packet_size(s, pid, ep, descriptors + i);
- break;
- case 0x02:
- type = USBDEVFS_URB_TYPE_BULK;
- break;
- case 0x03:
- type = USBDEVFS_URB_TYPE_INTERRUPT;
- break;
- default:
- DPRINTF("usb_host: malformed endpoint type\n");
- type = USBDEVFS_URB_TYPE_BULK;
- }
+ type = descriptors[i + 3] & 0x3;
+ raw = descriptors[i + 4] + (descriptors[i + 5] << 8);
+ usb_ep_set_max_packet_size(&s->dev, pid, ep, raw);
+ assert(usb_ep_get_type(&s->dev, pid, ep) ==
+ USB_ENDPOINT_XFER_INVALID);
+ usb_ep_set_type(&s->dev, pid, ep, type);
+ usb_ep_set_ifnum(&s->dev, pid, ep, interface);
+
epd = get_endp(s, pid, ep);
- assert(epd->type == INVALID_EP_TYPE);
- epd->type = type;
epd->halted = 0;
i += descriptors[i];
}
}
+#ifdef DEBUG
+ usb_ep_dump(&s->dev);
+#endif
return 0;
}
@@ -1273,7 +1240,6 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
const char *prod_name, int speed)
{
int fd = -1, ret;
- char buf[1024];
trace_usb_host_open_started(bus_num, addr);
@@ -1281,15 +1247,8 @@ static int usb_host_open(USBHostDevice *dev, int bus_num,
goto fail;
}
- if (!usb_host_device_path) {
- perror("husb: USB Host Device Path not set");
- goto fail;
- }
- snprintf(buf, sizeof(buf), "%s/%03d/%03d", usb_host_device_path,
- bus_num, addr);
- fd = open(buf, O_RDWR | O_NONBLOCK);
+ fd = usb_host_open_device(bus_num, addr);
if (fd < 0) {
- perror(buf);
goto fail;
}
DPRINTF("husb: opened %s\n", buf);
@@ -1390,7 +1349,7 @@ static int usb_host_close(USBHostDevice *dev)
qemu_set_fd_handler(dev->fd, NULL, NULL, NULL);
dev->closing = 1;
- for (i = 1; i <= MAX_ENDPOINTS; i++) {
+ for (i = 1; i <= USB_MAX_ENDPOINTS; i++) {
if (is_isoc(dev, USB_TOKEN_IN, i)) {
usb_host_stop_n_free_iso(dev, USB_TOKEN_IN, i);
}
@@ -1443,34 +1402,44 @@ static const VMStateDescription vmstate_usb_host = {
.unmigratable = 1,
};
-static struct USBDeviceInfo usb_host_dev_info = {
- .product_desc = "USB Host Device",
- .qdev.name = "usb-host",
- .qdev.size = sizeof(USBHostDevice),
- .qdev.vmsd = &vmstate_usb_host,
- .init = usb_host_initfn,
- .handle_packet = usb_generic_handle_packet,
- .cancel_packet = usb_host_async_cancel,
- .handle_data = usb_host_handle_data,
- .handle_control = usb_host_handle_control,
- .handle_reset = usb_host_handle_reset,
- .handle_destroy = usb_host_handle_destroy,
- .usbdevice_name = "host",
- .usbdevice_init = usb_host_device_open,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
- DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
- DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
- DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
- DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
- DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property usb_host_dev_properties[] = {
+ DEFINE_PROP_UINT32("hostbus", USBHostDevice, match.bus_num, 0),
+ DEFINE_PROP_UINT32("hostaddr", USBHostDevice, match.addr, 0),
+ DEFINE_PROP_STRING("hostport", USBHostDevice, match.port),
+ DEFINE_PROP_HEX32("vendorid", USBHostDevice, match.vendor_id, 0),
+ DEFINE_PROP_HEX32("productid", USBHostDevice, match.product_id, 0),
+ DEFINE_PROP_UINT32("isobufs", USBHostDevice, iso_urb_count, 4),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usb_host_class_initfn(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+
+ uc->init = usb_host_initfn;
+ uc->product_desc = "USB Host Device";
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->cancel_packet = usb_host_async_cancel;
+ uc->handle_data = usb_host_handle_data;
+ uc->handle_control = usb_host_handle_control;
+ uc->handle_reset = usb_host_handle_reset;
+ uc->handle_destroy = usb_host_handle_destroy;
+ dc->vmsd = &vmstate_usb_host;
+ dc->props = usb_host_dev_properties;
+}
+
+static TypeInfo usb_host_dev_info = {
+ .name = "usb-host",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBHostDevice),
+ .class_init = usb_host_class_initfn,
};
static void usb_host_register_devices(void)
{
- usb_qdev_register(&usb_host_dev_info);
+ type_register_static(&usb_host_dev_info);
+ usb_legacy_register("usb-host", "host", usb_host_device_open);
}
device_init(usb_host_register_devices)
@@ -1538,149 +1507,6 @@ int usb_host_device_close(const char *devname)
return -1;
}
-static int get_tag_value(char *buf, int buf_size,
- const char *str, const char *tag,
- const char *stopchars)
-{
- const char *p;
- char *q;
- p = strstr(str, tag);
- if (!p) {
- return -1;
- }
- p += strlen(tag);
- while (qemu_isspace(*p)) {
- p++;
- }
- q = buf;
- while (*p != '\0' && !strchr(stopchars, *p)) {
- if ((q - buf) < (buf_size - 1)) {
- *q++ = *p;
- }
- p++;
- }
- *q = '\0';
- return q - buf;
-}
-
-/*
- * Use /proc/bus/usb/devices or /dev/bus/usb/devices file to determine
- * host's USB devices. This is legacy support since many distributions
- * are moving to /sys/bus/usb
- */
-static int usb_host_scan_dev(void *opaque, USBScanFunc *func)
-{
- FILE *f = NULL;
- char line[1024];
- char buf[1024];
- int bus_num, addr, speed, device_count;
- int class_id, product_id, vendor_id, port;
- char product_name[512];
- int ret = 0;
-
- if (!usb_host_device_path) {
- perror("husb: USB Host Device Path not set");
- goto the_end;
- }
- snprintf(line, sizeof(line), "%s/devices", usb_host_device_path);
- f = fopen(line, "r");
- if (!f) {
- perror("husb: cannot open devices file");
- goto the_end;
- }
-
- device_count = 0;
- bus_num = addr = class_id = product_id = vendor_id = port = 0;
- speed = -1; /* Can't get the speed from /[proc|dev]/bus/usb/devices */
- for(;;) {
- if (fgets(line, sizeof(line), f) == NULL) {
- break;
- }
- if (strlen(line) > 0) {
- line[strlen(line) - 1] = '\0';
- }
- if (line[0] == 'T' && line[1] == ':') {
- if (device_count && (vendor_id || product_id)) {
- /* New device. Add the previously discovered device. */
- if (port > 0) {
- snprintf(buf, sizeof(buf), "%d", port);
- } else {
- snprintf(buf, sizeof(buf), "?");
- }
- ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
- product_id, product_name, speed);
- if (ret) {
- goto the_end;
- }
- }
- if (get_tag_value(buf, sizeof(buf), line, "Bus=", " ") < 0) {
- goto fail;
- }
- bus_num = atoi(buf);
- if (get_tag_value(buf, sizeof(buf), line, "Port=", " ") < 0) {
- goto fail;
- }
- port = atoi(buf);
- if (get_tag_value(buf, sizeof(buf), line, "Dev#=", " ") < 0) {
- goto fail;
- }
- addr = atoi(buf);
- if (get_tag_value(buf, sizeof(buf), line, "Spd=", " ") < 0) {
- goto fail;
- }
- if (!strcmp(buf, "5000")) {
- speed = USB_SPEED_SUPER;
- } else if (!strcmp(buf, "480")) {
- speed = USB_SPEED_HIGH;
- } else if (!strcmp(buf, "1.5")) {
- speed = USB_SPEED_LOW;
- } else {
- speed = USB_SPEED_FULL;
- }
- product_name[0] = '\0';
- class_id = 0xff;
- device_count++;
- product_id = 0;
- vendor_id = 0;
- } else if (line[0] == 'P' && line[1] == ':') {
- if (get_tag_value(buf, sizeof(buf), line, "Vendor=", " ") < 0) {
- goto fail;
- }
- vendor_id = strtoul(buf, NULL, 16);
- if (get_tag_value(buf, sizeof(buf), line, "ProdID=", " ") < 0) {
- goto fail;
- }
- product_id = strtoul(buf, NULL, 16);
- } else if (line[0] == 'S' && line[1] == ':') {
- if (get_tag_value(buf, sizeof(buf), line, "Product=", "") < 0) {
- goto fail;
- }
- pstrcpy(product_name, sizeof(product_name), buf);
- } else if (line[0] == 'D' && line[1] == ':') {
- if (get_tag_value(buf, sizeof(buf), line, "Cls=", " (") < 0) {
- goto fail;
- }
- class_id = strtoul(buf, NULL, 16);
- }
- fail: ;
- }
- if (device_count && (vendor_id || product_id)) {
- /* Add the last device. */
- if (port > 0) {
- snprintf(buf, sizeof(buf), "%d", port);
- } else {
- snprintf(buf, sizeof(buf), "?");
- }
- ret = func(opaque, bus_num, addr, buf, class_id, vendor_id,
- product_id, product_name, speed);
- }
- the_end:
- if (f) {
- fclose(f);
- }
- return ret;
-}
-
/*
* Read sys file-system device file
*
@@ -1698,7 +1524,7 @@ static int usb_host_read_file(char *line, size_t line_size,
int ret = 0;
char filename[PATH_MAX];
- snprintf(filename, PATH_MAX, USBSYSBUS_PATH "/devices/%s/%s", device_name,
+ snprintf(filename, PATH_MAX, "/sys/bus/usb/devices/%s/%s", device_name,
device_file);
f = fopen(filename, "r");
if (f) {
@@ -1716,7 +1542,7 @@ static int usb_host_read_file(char *line, size_t line_size,
* This code is based on Robert Schiele's original patches posted to
* the Novell bug-tracker https://bugzilla.novell.com/show_bug.cgi?id=241950
*/
-static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
+static int usb_host_scan(void *opaque, USBScanFunc *func)
{
DIR *dir = NULL;
char line[1024];
@@ -1726,9 +1552,10 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
char product_name[512];
struct dirent *de;
- dir = opendir(USBSYSBUS_PATH "/devices");
+ dir = opendir("/sys/bus/usb/devices");
if (!dir) {
- perror("husb: cannot open devices directory");
+ perror("husb: opendir /sys/bus/usb/devices");
+ fprintf(stderr, "husb: please make sure sysfs is mounted at /sys\n");
goto the_end;
}
@@ -1803,81 +1630,6 @@ static int usb_host_scan_sys(void *opaque, USBScanFunc *func)
return ret;
}
-/*
- * Determine how to access the host's USB devices and call the
- * specific support function.
- */
-static int usb_host_scan(void *opaque, USBScanFunc *func)
-{
- Monitor *mon = cur_mon;
- FILE *f = NULL;
- DIR *dir = NULL;
- int ret = 0;
- const char *fs_type[] = {"unknown", "proc", "dev", "sys"};
- char devpath[PATH_MAX];
-
- /* only check the host once */
- if (!usb_fs_type) {
- dir = opendir(USBSYSBUS_PATH "/devices");
- if (dir) {
- /* devices found in /dev/bus/usb/ (yes - not a mistake!) */
- strcpy(devpath, USBDEVBUS_PATH);
- usb_fs_type = USB_FS_SYS;
- closedir(dir);
- DPRINTF(USBDBG_DEVOPENED, USBSYSBUS_PATH);
- goto found_devices;
- }
- f = fopen(USBPROCBUS_PATH "/devices", "r");
- if (f) {
- /* devices found in /proc/bus/usb/ */
- strcpy(devpath, USBPROCBUS_PATH);
- usb_fs_type = USB_FS_PROC;
- fclose(f);
- DPRINTF(USBDBG_DEVOPENED, USBPROCBUS_PATH);
- goto found_devices;
- }
- /* try additional methods if an access method hasn't been found yet */
- f = fopen(USBDEVBUS_PATH "/devices", "r");
- if (f) {
- /* devices found in /dev/bus/usb/ */
- strcpy(devpath, USBDEVBUS_PATH);
- usb_fs_type = USB_FS_DEV;
- fclose(f);
- DPRINTF(USBDBG_DEVOPENED, USBDEVBUS_PATH);
- goto found_devices;
- }
- found_devices:
- if (!usb_fs_type) {
- if (mon) {
- monitor_printf(mon, "husb: unable to access USB devices\n");
- }
- return -ENOENT;
- }
-
- /* the module setting (used later for opening devices) */
- usb_host_device_path = g_malloc0(strlen(devpath)+1);
- strcpy(usb_host_device_path, devpath);
- if (mon) {
- monitor_printf(mon, "husb: using %s file-system with %s\n",
- fs_type[usb_fs_type], usb_host_device_path);
- }
- }
-
- switch (usb_fs_type) {
- case USB_FS_PROC:
- case USB_FS_DEV:
- ret = usb_host_scan_dev(opaque, func);
- break;
- case USB_FS_SYS:
- ret = usb_host_scan_sys(opaque, func);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
static QEMUTimer *usb_auto_timer;
static int usb_host_auto_scan(void *opaque, int bus_num,
diff --git a/usb-redir.c b/usb-redir.c
index 2b53cf30cc..303292acd6 100644
--- a/usb-redir.c
+++ b/usb-redir.c
@@ -60,7 +60,11 @@ struct endp_data {
uint8_t iso_error; /* For reporting iso errors to the HC */
uint8_t interrupt_started;
uint8_t interrupt_error;
+ uint8_t bufpq_prefilled;
+ uint8_t bufpq_dropping_packets;
QTAILQ_HEAD(, buf_packet) bufpq;
+ int bufpq_size;
+ int bufpq_target_size;
};
struct USBRedirDevice {
@@ -287,21 +291,41 @@ static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p)
}
}
-static struct buf_packet *bufp_alloc(USBRedirDevice *dev,
+static void bufp_alloc(USBRedirDevice *dev,
uint8_t *data, int len, int status, uint8_t ep)
{
- struct buf_packet *bufp = g_malloc(sizeof(struct buf_packet));
+ struct buf_packet *bufp;
+
+ if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets &&
+ dev->endpoint[EP2I(ep)].bufpq_size >
+ 2 * dev->endpoint[EP2I(ep)].bufpq_target_size) {
+ DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep);
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1;
+ }
+ /* Since we're interupting the stream anyways, drop enough packets to get
+ back to our target buffer size */
+ if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) {
+ if (dev->endpoint[EP2I(ep)].bufpq_size >
+ dev->endpoint[EP2I(ep)].bufpq_target_size) {
+ free(data);
+ return;
+ }
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
+ }
+
+ bufp = g_malloc(sizeof(struct buf_packet));
bufp->data = data;
bufp->len = len;
bufp->status = status;
QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
- return bufp;
+ dev->endpoint[EP2I(ep)].bufpq_size++;
}
static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp,
uint8_t ep)
{
QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next);
+ dev->endpoint[EP2I(ep)].bufpq_size--;
free(bufp->data);
g_free(bufp);
}
@@ -332,35 +356,77 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
uint8_t ep)
{
int status, len;
-
if (!dev->endpoint[EP2I(ep)].iso_started &&
!dev->endpoint[EP2I(ep)].iso_error) {
struct usb_redir_start_iso_stream_header start_iso = {
.endpoint = ep,
- /* TODO maybe do something with these depending on ep interval? */
- .pkts_per_urb = 32,
- .no_urbs = 3,
};
+ int pkts_per_sec;
+
+ if (dev->dev.speed == USB_SPEED_HIGH) {
+ pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval;
+ } else {
+ pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval;
+ }
+ /* Testing has shown that we need circa 60 ms buffer */
+ dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000;
+
+ /* Aim for approx 100 interrupts / second on the client to
+ balance latency and interrupt load */
+ start_iso.pkts_per_urb = pkts_per_sec / 100;
+ if (start_iso.pkts_per_urb < 1) {
+ start_iso.pkts_per_urb = 1;
+ } else if (start_iso.pkts_per_urb > 32) {
+ start_iso.pkts_per_urb = 32;
+ }
+
+ start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size +
+ start_iso.pkts_per_urb - 1) /
+ start_iso.pkts_per_urb;
+ /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest
+ as overflow buffer. Also see the usbredir protocol documentation */
+ if (!(ep & USB_DIR_IN)) {
+ start_iso.no_urbs *= 2;
+ }
+ if (start_iso.no_urbs > 16) {
+ start_iso.no_urbs = 16;
+ }
+
/* No id, we look at the ep when receiving a status back */
usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso);
usbredirparser_do_write(dev->parser);
- DPRINTF("iso stream started ep %02X\n", ep);
+ DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n",
+ pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep);
dev->endpoint[EP2I(ep)].iso_started = 1;
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
}
if (ep & USB_DIR_IN) {
struct buf_packet *isop;
+ if (dev->endpoint[EP2I(ep)].iso_started &&
+ !dev->endpoint[EP2I(ep)].bufpq_prefilled) {
+ if (dev->endpoint[EP2I(ep)].bufpq_size <
+ dev->endpoint[EP2I(ep)].bufpq_target_size) {
+ return usbredir_handle_status(dev, 0, 0);
+ }
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 1;
+ }
+
isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
if (isop == NULL) {
- DPRINTF2("iso-token-in ep %02X, no isop\n", ep);
+ DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n",
+ ep, dev->endpoint[EP2I(ep)].iso_error);
+ /* Re-fill the buffer */
+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0;
/* Check iso_error for stream errors, otherwise its an underrun */
status = dev->endpoint[EP2I(ep)].iso_error;
dev->endpoint[EP2I(ep)].iso_error = 0;
return usbredir_handle_status(dev, status, 0);
}
- DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status,
- isop->len);
+ DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep,
+ isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size);
status = isop->status;
if (status != usb_redir_success) {
@@ -370,7 +436,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p,
len = isop->len;
if (len > p->iov.size) {
- ERROR("received iso data is larger then packet ep %02X\n", ep);
+ ERROR("received iso data is larger then packet ep %02X (%d > %d)\n",
+ ep, len, (int)p->iov.size);
bufp_free(dev, isop, ep);
return USB_RET_NAK;
}
@@ -410,6 +477,7 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep)
DPRINTF("iso stream stopped ep %02X\n", ep);
dev->endpoint[EP2I(ep)].iso_started = 0;
}
+ dev->endpoint[EP2I(ep)].iso_error = 0;
usbredir_free_bufpq(dev, ep);
}
@@ -460,6 +528,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev,
usbredirparser_do_write(dev->parser);
DPRINTF("interrupt recv started ep %02X\n", ep);
dev->endpoint[EP2I(ep)].interrupt_started = 1;
+ /* We don't really want to drop interrupt packets ever, but
+ having some upper limit to how much we buffer is good. */
+ dev->endpoint[EP2I(ep)].bufpq_target_size = 1000;
+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0;
}
intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq);
@@ -522,6 +594,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev,
DPRINTF("interrupt recv stopped ep %02X\n", ep);
dev->endpoint[EP2I(ep)].interrupt_started = 0;
}
+ dev->endpoint[EP2I(ep)].interrupt_error = 0;
usbredir_free_bufpq(dev, ep);
}
@@ -959,9 +1032,24 @@ static void usbredir_ep_info(void *priv,
dev->endpoint[i].type = ep_info->type[i];
dev->endpoint[i].interval = ep_info->interval[i];
dev->endpoint[i].interface = ep_info->interface[i];
- if (dev->endpoint[i].type != usb_redir_type_invalid) {
+ switch (dev->endpoint[i].type) {
+ case usb_redir_type_invalid:
+ break;
+ case usb_redir_type_iso:
+ case usb_redir_type_interrupt:
+ if (dev->endpoint[i].interval == 0) {
+ ERROR("Received 0 interval for isoc or irq endpoint\n");
+ usbredir_device_disconnect(dev);
+ }
+ /* Fall through */
+ case usb_redir_type_control:
+ case usb_redir_type_bulk:
DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i),
dev->endpoint[i].type, dev->endpoint[i].interface);
+ break;
+ default:
+ ERROR("Received invalid endpoint type\n");
+ usbredir_device_disconnect(dev);
}
}
}
@@ -1029,7 +1117,7 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id,
DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status,
ep, id);
- if (!dev->dev.attached) {
+ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) {
return;
}
@@ -1050,7 +1138,7 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id,
DPRINTF("interrupt recv status %d ep %02X id %u\n",
interrupt_receiving_status->status, ep, id);
- if (!dev->dev.attached) {
+ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) {
return;
}
@@ -1227,26 +1315,37 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id,
}
}
-static struct USBDeviceInfo usbredir_dev_info = {
- .product_desc = "USB Redirection Device",
- .qdev.name = "usb-redir",
- .qdev.size = sizeof(USBRedirDevice),
- .init = usbredir_initfn,
- .handle_destroy = usbredir_handle_destroy,
- .handle_packet = usb_generic_handle_packet,
- .cancel_packet = usbredir_cancel_packet,
- .handle_reset = usbredir_handle_reset,
- .handle_data = usbredir_handle_data,
- .handle_control = usbredir_handle_control,
- .qdev.props = (Property[]) {
- DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
- DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
- DEFINE_PROP_END_OF_LIST(),
- },
+static Property usbredir_properties[] = {
+ DEFINE_PROP_CHR("chardev", USBRedirDevice, cs),
+ DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void usbredir_class_initfn(ObjectClass *klass, void *data)
+{
+ USBDeviceClass *uc = USB_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ uc->init = usbredir_initfn;
+ uc->product_desc = "USB Redirection Device";
+ uc->handle_destroy = usbredir_handle_destroy;
+ uc->handle_packet = usb_generic_handle_packet;
+ uc->cancel_packet = usbredir_cancel_packet;
+ uc->handle_reset = usbredir_handle_reset;
+ uc->handle_data = usbredir_handle_data;
+ uc->handle_control = usbredir_handle_control;
+ dc->props = usbredir_properties;
+}
+
+static TypeInfo usbredir_dev_info = {
+ .name = "usb-redir",
+ .parent = TYPE_USB_DEVICE,
+ .instance_size = sizeof(USBRedirDevice),
+ .class_init = usbredir_class_initfn,
};
static void usbredir_register_devices(void)
{
- usb_qdev_register(&usbredir_dev_info);
+ type_register_static(&usbredir_dev_info);
}
device_init(usbredir_register_devices);
diff --git a/vl.c b/vl.c
index ba55b356cf..63dd725216 100644
--- a/vl.c
+++ b/vl.c
@@ -201,7 +201,6 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
int win2k_install_hack = 0;
-int rtc_td_hack = 0;
int usb_enabled = 0;
int singlestep = 0;
int smp_cpus = 1;
@@ -218,7 +217,6 @@ int no_reboot = 0;
int no_shutdown = 0;
int cursor_hide = 1;
int graphic_rotate = 0;
-uint8_t irq0override = 1;
const char *watchdog;
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
@@ -271,7 +269,6 @@ static int default_serial = 1;
static int default_parallel = 1;
static int default_virtcon = 1;
static int default_monitor = 1;
-static int default_vga = 1;
static int default_floppy = 1;
static int default_cdrom = 1;
static int default_sdcard = 1;
@@ -290,11 +287,6 @@ static struct {
{ .driver = "virtio-serial-pci", .flag = &default_virtcon },
{ .driver = "virtio-serial-s390", .flag = &default_virtcon },
{ .driver = "virtio-serial", .flag = &default_virtcon },
- { .driver = "VGA", .flag = &default_vga },
- { .driver = "cirrus-vga", .flag = &default_vga },
- { .driver = "vmware-svga", .flag = &default_vga },
- { .driver = "isa-vga", .flag = &default_vga },
- { .driver = "qxl-vga", .flag = &default_vga },
};
static void res_free(void)
@@ -547,9 +539,18 @@ static void configure_rtc(QemuOpts *opts)
value = qemu_opt_get(opts, "driftfix");
if (value) {
if (!strcmp(value, "slew")) {
- rtc_td_hack = 1;
+ static GlobalProperty slew_lost_ticks[] = {
+ {
+ .driver = "mc146818rtc",
+ .property = "lost_tick_policy",
+ .value = "slew",
+ },
+ { /* end of list */ }
+ };
+
+ qdev_prop_register_global_list(slew_lost_ticks);
} else if (!strcmp(value, "none")) {
- rtc_td_hack = 0;
+ /* discard is default */
} else {
fprintf(stderr, "qemu: invalid option value '%s'\n", value);
exit(1);
@@ -1525,18 +1526,48 @@ static const QEMUOption qemu_options[] = {
#include "qemu-options-wrapper.h"
{ NULL },
};
+
+static bool vga_available(void)
+{
+ return qdev_exists("VGA") || qdev_exists("isa-vga");
+}
+
+static bool cirrus_vga_available(void)
+{
+ return qdev_exists("cirrus-vga") || qdev_exists("isa-cirrus-vga");
+}
+
+static bool vmware_vga_available(void)
+{
+ return qdev_exists("vmware-svga");
+}
+
static void select_vgahw (const char *p)
{
const char *opts;
- default_vga = 0;
vga_interface_type = VGA_NONE;
if (strstart(p, "std", &opts)) {
- vga_interface_type = VGA_STD;
+ if (vga_available()) {
+ vga_interface_type = VGA_STD;
+ } else {
+ fprintf(stderr, "Error: standard VGA not available\n");
+ exit(0);
+ }
} else if (strstart(p, "cirrus", &opts)) {
- vga_interface_type = VGA_CIRRUS;
+ if (cirrus_vga_available()) {
+ vga_interface_type = VGA_CIRRUS;
+ } else {
+ fprintf(stderr, "Error: Cirrus VGA not available\n");
+ exit(0);
+ }
} else if (strstart(p, "vmware", &opts)) {
- vga_interface_type = VGA_VMWARE;
+ if (vmware_vga_available()) {
+ vga_interface_type = VGA_VMWARE;
+ } else {
+ fprintf(stderr, "Error: VMWare SVGA not available\n");
+ exit(0);
+ }
} else if (strstart(p, "xenfb", &opts)) {
vga_interface_type = VGA_XENFB;
} else if (strstart(p, "qxl", &opts)) {
@@ -1916,7 +1947,11 @@ static int virtcon_parse(const char *devname)
}
bus_opts = qemu_opts_create(device, NULL, 0);
- qemu_opt_set(bus_opts, "driver", "virtio-serial");
+ if (arch_type == QEMU_ARCH_S390X) {
+ qemu_opt_set(bus_opts, "driver", "virtio-serial-s390");
+ } else {
+ qemu_opt_set(bus_opts, "driver", "virtio-serial-pci");
+ }
dev_opts = qemu_opts_create(device, NULL, 0);
qemu_opt_set(dev_opts, "driver", "virtconsole");
@@ -2136,6 +2171,11 @@ static void free_and_trace(gpointer mem)
free(mem);
}
+int qemu_init_main_loop(void)
+{
+ return main_loop_init();
+}
+
int main(int argc, char **argv, char **envp)
{
const char *gdbstub_dev = NULL;
@@ -2155,6 +2195,7 @@ int main(int argc, char **argv, char **envp)
const char *loadvm = NULL;
QEMUMachine *machine;
const char *cpu_model;
+ const char *vga_model = NULL;
const char *pid_file = NULL;
const char *incoming = NULL;
#ifdef CONFIG_VNC
@@ -2581,7 +2622,7 @@ int main(int argc, char **argv, char **envp)
rtc_utc = 0;
break;
case QEMU_OPTION_vga:
- select_vgahw (optarg);
+ vga_model = optarg;
break;
case QEMU_OPTION_g:
{
@@ -2812,9 +2853,19 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_win2k_hack:
win2k_install_hack = 1;
break;
- case QEMU_OPTION_rtc_td_hack:
- rtc_td_hack = 1;
+ case QEMU_OPTION_rtc_td_hack: {
+ static GlobalProperty slew_lost_ticks[] = {
+ {
+ .driver = "mc146818rtc",
+ .property = "lost_tick_policy",
+ .value = "slew",
+ },
+ { /* end of list */ }
+ };
+
+ qdev_prop_register_global_list(slew_lost_ticks);
break;
+ }
case QEMU_OPTION_acpitable:
do_acpitable_option(optarg);
break;
@@ -2978,11 +3029,11 @@ int main(int argc, char **argv, char **envp)
default_parallel = 0;
default_virtcon = 0;
default_monitor = 0;
- default_vga = 0;
default_net = 0;
default_floppy = 0;
default_cdrom = 0;
default_sdcard = 0;
+ vga_model = "none";
break;
case QEMU_OPTION_xen_domid:
if (!(xen_available())) {
@@ -3111,21 +3162,8 @@ int main(int argc, char **argv, char **envp)
* specified either by the configuration file or by the command line.
*/
if (machine->default_machine_opts) {
- QemuOptsList *list = qemu_find_opts("machine");
- const char *p = NULL;
-
- if (!QTAILQ_EMPTY(&list->head)) {
- p = qemu_opt_get(QTAILQ_FIRST(&list->head), "accel");
- }
- if (p == NULL) {
- qemu_opts_reset(list);
- opts = qemu_opts_parse(list, machine->default_machine_opts, 0);
- if (!opts) {
- fprintf(stderr, "parse error for machine %s: %s\n",
- machine->name, machine->default_machine_opts);
- exit(1);
- }
- }
+ qemu_opts_set_defaults(qemu_find_opts("machine"),
+ machine->default_machine_opts, 0);
}
qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0);
@@ -3140,9 +3178,6 @@ int main(int argc, char **argv, char **envp)
if (!machine->use_virtcon) {
default_virtcon = 0;
}
- if (machine->no_vga) {
- default_vga = 0;
- }
if (machine->no_floppy) {
default_floppy = 0;
}
@@ -3178,8 +3213,6 @@ int main(int argc, char **argv, char **envp)
if (default_virtcon)
add_device_config(DEV_VIRTCON, "vc:80Cx24C");
}
- if (default_vga)
- vga_interface_type = VGA_CIRRUS;
socket_init();
@@ -3330,6 +3363,15 @@ int main(int argc, char **argv, char **envp)
module_call_init(MODULE_INIT_DEVICE);
+ /* must be after qdev registration but before machine init */
+ if (vga_model) {
+ select_vgahw(vga_model);
+ } else if (cirrus_vga_available()) {
+ select_vgahw("cirrus");
+ } else {
+ select_vgahw("none");
+ }
+
if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
exit(0);
diff --git a/xen-all.c b/xen-all.c
index d1fc5972c7..fd3916857c 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -447,7 +447,8 @@ static void xen_sync_dirty_bitmap(XenIOState *state,
j = ffsl(map) - 1;
map &= ~(1ul << j);
memory_region_set_dirty(framebuffer,
- (i * width + j) * TARGET_PAGE_SIZE);
+ (i * width + j) * TARGET_PAGE_SIZE,
+ TARGET_PAGE_SIZE);
};
}
}